Railway Operation Simulator  v2.13.0
A railway simulator for Windows
TrackUnit.cpp
Go to the documentation of this file.
1 // TrackUnit.cpp
2 /*
3  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
4  sometimes been overtaken by changes and not updated
5  Comments in .h files are believed to be accurate and up to date
6 
7  This is a source code file for "railway.exe", a railway operation
8  simulator, written originally in Borland C++ Builder 4 Professional with
9  later updates in Embarcadero C++Builder 10.2.
10  Copyright (C) 2010 Albert Ball [original development]
11 
12  This program is free software: you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25 // ---------------------------------------------------------------------------
26 #include <Classes.hpp>
27 #include <Controls.hpp>
28 #include <StdCtrls.hpp>
29 #include <Forms.hpp>
30 #include <Buttons.hpp>
31 #include <ExtCtrls.hpp>
32 #include <Menus.hpp>
33 #include <Dialogs.hpp>
34 #include <Graphics.hpp>
35 #include <ComCtrls.hpp>
36 #include <fstream>
37 #include <vector>
38 #include <algorithm> //for std::find
39 #include <vcl.h>
40 
41 #pragma hdrstop
42 
43 #include "TrackUnit.h"
44 #include "TrainUnit.h"
45 #include "GraphicUnit.h"
46 //#include "DisplayUnit.h" included in TrackUnit.h
47 #include "TextUnit.h"
48 #include "PerfLogUnit.h"
49 #include "Utilities.h"
50 
51 #pragma package(smart_init)
52 // ---------------------------------------------------------------------------
53 
56 
57 // ---------------------------------------------------------------------------
58 
59 // FIXED TRACK :-
60 
61 // Constructor to build TrackPieces from array
62 
63 TFixedTrackPiece::TFixedTrackPiece(int SpeedTagVal, TTrackType TrackTypeVal, int LkVal[4], TConfiguration ConfigVal[4], Graphics::TBitmap* GraphicPtrVal,
64  Graphics::TBitmap* SmallGraphicPtrVal) : SpeedTag(SpeedTagVal), TrackType(TrackTypeVal), GraphicPtr(GraphicPtrVal), SmallGraphicPtr(SmallGraphicPtrVal)
65 {
66  for(int x = 0; x < 4; x++)
67  {
68  Link[x] = LkVal[x];
69  Config[x] = ConfigVal[x];
70  }
71 // NamedLocationElements 76, 77, 78, 79, 96, 129, 130, 131, 145 & 146 (platforms, concourses, footcrossings & named non-station locations)
72  FixedNamedLocationElement = false; // underpasses (144 & 145 added at v2.3.1
73  if(SpeedTagVal == 76)
74  {
76  }
77  else if(SpeedTagVal == 77)
78  {
80  }
81  else if(SpeedTagVal == 78)
82  {
84  }
85  else if(SpeedTagVal == 79)
86  {
88  }
89  else if(SpeedTagVal == 96)
90  {
92  }
93  else if(SpeedTagVal == 129)
94  {
96  }
97  else if(SpeedTagVal == 130)
98  {
100  }
101  else if(SpeedTagVal == 131)
102  {
104  }
105  else if(SpeedTagVal == 145)
106  {
108  }
109  else if(SpeedTagVal == 146)
110  {
112  }
113 }
114 
115 // ---------------------------------------------------------------------------
116 
117 TFixedTrackPiece::TFixedTrackPiece() : SpeedTag(0), TrackType(Erase), GraphicPtr(RailGraphics->bmSolidBgnd), SmallGraphicPtr(RailGraphics->smSolidBgnd),
118  FixedNamedLocationElement(false) // default values
119 {
120  for(int x = 0; x < 4; x++)
121  {
122  Link[x] = -1; // -1 & NotSet are the markers for 'unused' respectively
123  Config[x] = NotSet;
124  }
125 }
126 
127 // ---------------------------------------------------------------------------
128 void TFixedTrackPiece::PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
129 {
130  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotFixedTrackElement," + AnsiString(HLocInput) + "," +
131  AnsiString(VLocInput));
132  Display->PlotOutput(33, HLocInput * 16, VLocInput * 16, GraphicPtr);
133  Utilities->CallLogPop(1331);
134 }
135 
136 // ---------------------------------------------------------------------------
137 
138 // VARIABLE TRACK :-
139 
140 // ---------------------------------------------------------------------------
141 
143 {
144  if((this->HLoc == RHElement.HLoc) && (this->VLoc == RHElement.VLoc) && (this->SpeedTag == RHElement.SpeedTag))
145  {
146  return(true);
147  }
148  else
149  {
150  return(false);
151  }
152 }
153 
154 // ---------------------------------------------------------------------------
155 
157 {
158  if((this->HLoc != RHElement.HLoc) || (this->VLoc != RHElement.VLoc) || (this->SpeedTag != RHElement.SpeedTag))
159  {
160  return(true);
161  }
162  else
163  {
164  return(false);
165  }
166 }
167 
168 // ---------------------------------------------------------------------------
169 
171 // 'Variable' in the sense that element might be striped or non-striped
172 {
173  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotVariableTrackElement");
174  Graphics::TBitmap *GraphicOutput = GraphicPtr;
175 
176  if(LocationName == "")
177  {
178  switch(SpeedTag)
179  {
180  case 76: // t platform
181  GraphicOutput = RailGraphics->gl76Striped;
182  break;
183 
184  case 77: // h platform
185  GraphicOutput = RailGraphics->bm77Striped;
186  break;
187 
188  case 78: // v platform
189  GraphicOutput = RailGraphics->bm78Striped;
190  break;
191 
192  case 79: // r platform
193  GraphicOutput = RailGraphics->gl79Striped;
194  break;
195 
196  case 96: // concourse
197  GraphicOutput = RailGraphics->ConcourseStriped;
198  break;
199 
200  case 129: // v footbridge
201  GraphicOutput = RailGraphics->gl129Striped;
202  break;
203 
204  case 130: // h footbridge
205  GraphicOutput = RailGraphics->gl130Striped;
206  break;
207 
208  case 131: // non-station named loc
209  GraphicOutput = RailGraphics->bmNameStriped;
210  break;
211 
212  case 145: // v underpass
213  GraphicOutput = RailGraphics->gl145Striped;
214  break;
215 
216  case 146: // h underpass
217  GraphicOutput = RailGraphics->gl146Striped;
218  break;
219 
220  default:
221  GraphicOutput = GraphicPtr;
222  break;
223  }
224  }
225  Disp->PlotOutput(34, HLoc * 16, VLoc * 16, GraphicOutput);
226  //deal with TSRs
227  if((TrackType == Simple) && Failed) //added at v2.13.0
228  {
229  Disp->GetImage()->Canvas->Draw((HLoc - Display->DisplayOffsetH) * 16, (VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
230  }
231  Utilities->CallLogPop(1332);
232 }
233 
234 // ---------------------------------------------------------------------------
235 
236 AnsiString TTrackElement::LogTrack(int Caller) const
237 // for debugging when passes as a call parameter
238 {
239  AnsiString LogString = "TrkEl:-," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," +
240  AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit01) + "," + AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit23) + ",EndTrkEl,";
241 
242  return(LogString);
243 }
244 
245 // ---------------------------------------------------------------------------
246 
248  TTrackElement::TTrackElement(TFixedTrackPiece Input) : TFixedTrackPiece(Input), HLoc(-2000000000), VLoc(-2000000000), LocationName(""), ActiveTrackElementName(""),
249  Attribute(0), CallingOnSet(false), Length01(Track->DefaultTrackLength), Length23(-1), SpeedLimit01(Track->DefaultTrackSpeedLimit), SpeedLimit23(-1),
250  TrainIDOnElement(-1), TrainIDOnBridgeOrFailedPointOrigSpeedLimit01(-1), TrainIDOnBridgeOrFailedPointOrigSpeedLimit23(-1), StationEntryStopLinkPos1(-1), StationEntryStopLinkPos2(-1),
251  SigAspect(FourAspect)
252  {
253  Failed = false; //added at v2.13.0
254  for(int x = 0; x < 4; x++)
255  {
256  ConnLinkPos[x] = -1;
257  Conn[x] = -1;
258  }
259  if((TrackType == Points) || (TrackType == Crossover) || (TrackType == Bridge))
260  {
263  }
264  }
265 
266 // ---------------------------------------------------------------------------
267 
268 bool TMapComp:: operator()(const THVPair& lower, const THVPair& higher) const // HLoc VLoc
269 {
270  if(lower.second < higher.second)
271  {
272  return(true);
273  }
274  else if(lower.second > higher.second)
275  {
276  return(false);
277  }
278  else if(lower.second == higher.second)
279  {
280  if(lower.first < higher.first)
281  {
282  return(true);
283  }
284  }
285  return(false);
286 }
287 
288 // ---------------------------------------------------------------------------
289 // PrefDirElement Functions
290 // ---------------------------------------------------------------------------
291 
292 TPrefDirElement::TPrefDirElement(TTrackElement ElementIn, int ELinkIn, int ELinkPosIn, int XLinkIn, int XLinkPosIn, int TrackVectorPositionIn)
293  : TTrackElement(ElementIn), ELink(ELinkIn), ELinkPos(ELinkPosIn), XLink(XLinkIn), XLinkPos(XLinkPosIn), TrackVectorPosition(TrackVectorPositionIn),
294  CheckCount(9), IsARoute(false), AutoSignals(false), PrefDirRoute(false)
295 {
296  if(!EntryExitNumber())
297  {
298  throw Exception("EXNumber failure in TPrefDirElement constructor");
299  }
302 }
303 
304 // ---------------------------------------------------------------------------
305 
306 AnsiString TPrefDirElement::LogPrefDir() const
307 // for debugging when passed as a call parameter
308 {
309  AnsiString LogString = "PthEl:-," + AnsiString(ELink) + "," + AnsiString(ELinkPos) + "," + AnsiString(XLink) + "," + AnsiString(XLinkPos) + "," +
310  AnsiString(EXNumber) + "," + AnsiString(TrackVectorPosition) + "," + AnsiString((short)AutoSignals) + "," + AnsiString((short)PrefDirRoute) +
311  ",ElementID," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," + AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit01) + "," +
313 
314 // Track->TrackElementAt(73, TrackVectorPosition).LogTrack(12);
315  return(LogString);
316 }
317 
318 // ---------------------------------------------------------------------------
319 
320 bool TPrefDirElement::EntryExitNumber() // true for valid number
321 /*
322  Computes a number corresponding to ELink & Xlink if set, or to the entry and exit link values for the track
323  at Link[0] and Link[1], or, if ELink or XLink not set, and a complex (4-entry) element, return false for error message.
324  This should be OK because only elements for which ELink & XLink not set are PrefDir/route start elements and leading points
325  as temporary end of PrefDir, and in both cases this function is not called as the direction is not displayed for these elements.
326  Uses simple links between any 2 entry & exit points for use in displaying PrefDir or route graphics, or original graphic during
327  route flashing. Should only be called when ELink & XLink set, or when ELinkPos & XLinkPos set deliberately from a
328  TTrackElement during route setting functions. If a bridge then an additional check is made in case the graphic needed
329  corresponds to an undebridge, i.e a gap needed between entry and exit. In this case the EXNumber is increased by
330  16 so as to be unique. Returns true if valid and sets EXNumber to the selected value.
331 */
332 
333 {
334  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EntryExitNumber");
335  int EXArray[16][2] =
336  {{4, 6}, {2, 8}, // horizontal & vertical
337  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
338  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
339  {1, 9}, {3, 7}}; // forward & reverse diagonals
340 
341  int EXNum = -1;
342  int Entry, Exit;
343 
344  if(ELink > -1)
345  {
346  Entry = ELink; // pick up simple elements even if ELink &/or XLink not set, as no ambiguity
347  }
348  else if(Link[2] == -1)
349  {
350  Entry = Link[0];
351  }
352  else
353  {
354  Utilities->CallLogPop(122);
355  return(false);
356  }
357  if(XLink > -1)
358  {
359  Exit = XLink;
360  }
361  else if(Link[2] == -1)
362  {
363  Exit = Link[1];
364  }
365  else
366  {
367  Utilities->CallLogPop(123);
368  return(false);
369  }
370  for(int x = 0; x < 16; x++)
371  {
372  if(((Entry == EXArray[x][0]) && (Exit == EXArray[x][1])) || ((Entry == EXArray[x][1]) && (Exit == EXArray[x][0]))) //added extra brackets round && segments at v2.9.1
373  {
374  EXNum = x;
375  }
376  }
377  if(EXNum == -1)
378  {
379  Utilities->CallLogPop(124);
380  return(false);
381  }
382  int BrNum = -1;
383 
384 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
385  the graphic for each of which is different because of the shape of the overbridge. The basic
386  entry/exit value is computed above, and this used to select only from elements with that entry/exit
387  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
388  int BrEXArray[24][2] = {
389  {4,6},{2,8},{1,9},{3,7},
390  {1,9},{3,7},{1,9},{3,7},
391  {2,8},{4,6},{2,8},{4,6}
392 */
393 
394  if(TrackType == Bridge)
395  {
396  if(EXNum == 1)
397  {
398  if(SpeedTag == 49)
399  {
400  BrNum = 1 + 16;
401  }
402  else if(SpeedTag == 54)
403  {
404  BrNum = 8 + 16;
405  }
406  else if(SpeedTag == 55)
407  {
408  BrNum = 10 + 16;
409  }
410  }
411  else if(EXNum == 0)
412  {
413  if(SpeedTag == 48)
414  {
415  BrNum = 0 + 16;
416  }
417  else if(SpeedTag == 58)
418  {
419  BrNum = 11 + 16;
420  }
421  else if(SpeedTag == 59)
422  {
423  BrNum = 9 + 16;
424  }
425  }
426  else if(EXNum == 14)
427  {
428  if(SpeedTag == 50)
429  {
430  BrNum = 2 + 16;
431  }
432  else if(SpeedTag == 52)
433  {
434  BrNum = 4 + 16;
435  }
436  else if(SpeedTag == 57)
437  {
438  BrNum = 6 + 16;
439  }
440  }
441  else if(EXNum == 15)
442  {
443  if(SpeedTag == 51)
444  {
445  BrNum = 3 + 16;
446  }
447  else if(SpeedTag == 53)
448  {
449  BrNum = 7 + 16;
450  }
451  else if(SpeedTag == 56)
452  {
453  BrNum = 5 + 16;
454  }
455  }
456  }
457  if(BrNum == -1)
458  {
459  EXNumber = EXNum;
460  }
461  else
462  {
463  EXNumber = BrNum;
464  }
465  Utilities->CallLogPop(125);
466  return(true);
467 }
468 
469 // ---------------------------------------------------------------------------
470 
472 /*
473  This is the basic track graphic for use in plotting the original graphic during route flashing.
474  Enter with all set apart from EXGraphic & EntryDirectionGraphic
475 */
476 {
477  if(SpeedTag == 64)
478  {
479  return(RailGraphics->LinkGraphicsPtr[16]); // intercept diagonal buffers
480 
481  }
482  if(SpeedTag == 65)
483  {
484  return(RailGraphics->LinkGraphicsPtr[17]);
485  }
486  if(SpeedTag == 66)
487  {
488  return(RailGraphics->LinkGraphicsPtr[18]);
489  }
490  if(SpeedTag == 67)
491  {
492  return(RailGraphics->LinkGraphicsPtr[19]);
493  }
494  if(SpeedTag == 80)
495  {
496  return(RailGraphics->LinkGraphicsPtr[20]); // intercept continuations
497 
498  }
499  if(SpeedTag == 81)
500  {
501  return(RailGraphics->LinkGraphicsPtr[21]);
502  }
503  if(SpeedTag == 82)
504  {
505  return(RailGraphics->LinkGraphicsPtr[22]);
506  }
507  if(SpeedTag == 83)
508  {
509  return(RailGraphics->LinkGraphicsPtr[23]);
510  }
511  if(SpeedTag == 84)
512  {
513  return(RailGraphics->LinkGraphicsPtr[24]);
514  }
515  if(SpeedTag == 85)
516  {
517  return(RailGraphics->LinkGraphicsPtr[25]);
518  }
519  if(SpeedTag == 86)
520  {
521  return(RailGraphics->LinkGraphicsPtr[26]);
522  }
523  if(SpeedTag == 87)
524  {
525  return(RailGraphics->LinkGraphicsPtr[27]);
526  }
527  if(SpeedTag == 129)
528  {
529  return(RailGraphics->LinkGraphicsPtr[28]); // intercept under footbridges
530 
531  }
532  if(SpeedTag == 130)
533  {
534  return(RailGraphics->LinkGraphicsPtr[29]);
535  }
536  if(XLinkPos == -1) // not set, could be first element or last element = leading point
537  {
538 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or
539 // Points & don't want to display these)
540  if(Link[2] != -1)
541  {
542  return(0); // i.e. complex element, don't display
543  }
544  else
545  {
546  if(!EntryExitNumber())
547  {
548  throw Exception("Error in EntryExitNumber 4");
549  }
550  else
551  {
553  }
554  }
555  }
556  if(EXNumber > 15) // underbridge
557  {
558  return(RailGraphics->BridgeGraphicsPtr[EXNumber - 16]);
559  }
560  else
561  {
563  }
564 }
565 
566 // ---------------------------------------------------------------------------
567 
569 /*
570  As above but for PrefDir graphics.
571 */
572 {
573  if(SpeedTag == 64)
574  {
575  return(RailGraphics->LinkPrefDirGraphicsPtr[16]); // intercept diagonal buffers
576 
577  }
578  if(SpeedTag == 65)
579  {
581  }
582  if(SpeedTag == 66)
583  {
585  }
586  if(SpeedTag == 67)
587  {
589  }
590  if(SpeedTag == 80)
591  {
592  return(RailGraphics->LinkPrefDirGraphicsPtr[20]); // intercept continuations
593 
594  }
595  if(SpeedTag == 81)
596  {
598  }
599  if(SpeedTag == 82)
600  {
602  }
603  if(SpeedTag == 83)
604  {
606  }
607  if(SpeedTag == 84)
608  {
610  }
611  if(SpeedTag == 85)
612  {
614  }
615  if(SpeedTag == 86)
616  {
618  }
619  if(SpeedTag == 87)
620  {
622  }
623  if(SpeedTag == 129)
624  {
625  return(RailGraphics->LinkPrefDirGraphicsPtr[28]); // intercept under footbridges
626 
627  }
628  if(SpeedTag == 130)
629  {
631  }
632  if(XLinkPos == -1) // not set, could be first element or last element = leading point
633  {
634 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
635  if(Link[2] != -1)
636  {
637  return(0); // i.e. complex element, don't display
638  }
639  else
640  {
641  if(!EntryExitNumber())
642  {
643  throw Exception("Error in EntryExitNumber 5");
644  }
645  else
646  {
648  }
649  }
650  }
651  if(EXNumber > 15) // underbridge
652  {
654  }
655  else
656  {
658  }
659 }
660 
661 // ---------------------------------------------------------------------------
662 
663 Graphics::TBitmap *TPrefDirElement::GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
664 /*
665  As above but for route graphics.
666 */
667 {
668  if(!AutoSigsFlag && !PrefDirRoute)
669  {
670  if(SpeedTag == 64)
671  {
672  return(RailGraphics->LinkNonSigRouteGraphicsPtr[16]); // intercept diagonal buffers
673  }
674  if(SpeedTag == 65)
675  {
677  }
678  if(SpeedTag == 66)
679  {
681  }
682  if(SpeedTag == 67)
683  {
685  }
686  if(SpeedTag == 80)
687  {
688  return(RailGraphics->LinkNonSigRouteGraphicsPtr[20]); // intercept continuations
689  }
690  if(SpeedTag == 81)
691  {
693  }
694  if(SpeedTag == 82)
695  {
697  }
698  if(SpeedTag == 83)
699  {
701  }
702  if(SpeedTag == 84)
703  {
705  }
706  if(SpeedTag == 85)
707  {
709  }
710  if(SpeedTag == 86)
711  {
713  }
714  if(SpeedTag == 87)
715  {
717  }
718  if(SpeedTag == 129)
719  {
720  return(RailGraphics->LinkNonSigRouteGraphicsPtr[28]); // intercept under footbridges
721  }
722  if(SpeedTag == 130)
723  {
725  }
726  if(XLinkPos == -1) // not set, could be first element or last element = leading point
727  {
728  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
729  if(Link[2] != -1)
730  {
731  return(0); // i.e. complex element, don't display
732  }
733  else
734  {
735  if(!EntryExitNumber())
736  {
737  throw Exception("Error in EntryExitNumber 6");
738  }
739  else
740  {
742  }
743  }
744  }
745  if(EXNumber > 15) // underbridge
746  {
748  }
749  else
750  {
752  }
753  }
754 
755  else if(!AutoSigsFlag && PrefDirRoute)
756  {
757  if(SpeedTag == 64)
758  {
759  return(RailGraphics->LinkSigRouteGraphicsPtr[16]); // intercept diagonal buffers
760  }
761  if(SpeedTag == 65)
762  {
764  }
765  if(SpeedTag == 66)
766  {
768  }
769  if(SpeedTag == 67)
770  {
772  }
773  if(SpeedTag == 80)
774  {
775  return(RailGraphics->LinkSigRouteGraphicsPtr[20]); // intercept continuations
776  }
777  if(SpeedTag == 81)
778  {
780  }
781  if(SpeedTag == 82)
782  {
784  }
785  if(SpeedTag == 83)
786  {
788  }
789  if(SpeedTag == 84)
790  {
792  }
793  if(SpeedTag == 85)
794  {
796  }
797  if(SpeedTag == 86)
798  {
800  }
801  if(SpeedTag == 87)
802  {
804  }
805  if(SpeedTag == 129)
806  {
807  return(RailGraphics->LinkSigRouteGraphicsPtr[28]); // intercept under footbridges
808  }
809  if(SpeedTag == 130)
810  {
812  }
813  if(XLinkPos == -1) // not set, could be first element or last element = leading point
814  {
815  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
816  if(Link[2] != -1)
817  {
818  return(0); // i.e. complex element, don't display
819  }
820  else
821  {
822  if(!EntryExitNumber())
823  {
824  throw Exception("Error in EntryExitNumber 10");
825  }
826  else
827  {
829  }
830  }
831  }
832  if(EXNumber > 15) // underbridge
833  {
835  }
836  else
837  {
839  }
840  }
841 
842  else
843  {
844  if(SpeedTag == 64)
845  {
846  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
847  }
848  if(SpeedTag == 65)
849  {
851  }
852  if(SpeedTag == 66)
853  {
855  }
856  if(SpeedTag == 67)
857  {
859  }
860  if(SpeedTag == 80)
861  {
862  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
863 
864  }
865  if(SpeedTag == 81)
866  {
868  }
869  if(SpeedTag == 82)
870  {
872  }
873  if(SpeedTag == 83)
874  {
876  }
877  if(SpeedTag == 84)
878  {
880  }
881  if(SpeedTag == 85)
882  {
884  }
885  if(SpeedTag == 86)
886  {
888  }
889  if(SpeedTag == 87)
890  {
892  }
893  if(SpeedTag == 129)
894  {
895  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
896 
897  }
898  if(SpeedTag == 130)
899  {
901  }
902  if(XLinkPos == -1) // not set, could be first element or last element = leading point
903  {
904  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
905  if(Link[2] != -1)
906  {
907  return(0); // i.e. complex element, don't display
908  }
909  else
910  {
911  if(!EntryExitNumber())
912  {
913  throw Exception("Error in EntryExitNumber 11");
914  }
915  else
916  {
918  }
919  }
920  }
921  if(EXNumber > 15) // underbridge
922  {
924  }
925  else
926  {
928  }
929  }
930 }
931 
932 // ---------------------------------------------------------------------------
933 
935 /*
936  As above but for route flashing graphics. (Disused - now combined with above)
937 */
938 {
939  if(SpeedTag == 64)
940  {
941  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
942 
943  }
944  if(SpeedTag == 65)
945  {
947  }
948  if(SpeedTag == 66)
949  {
951  }
952  if(SpeedTag == 67)
953  {
955  }
956  if(SpeedTag == 80)
957  {
958  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
959 
960  }
961  if(SpeedTag == 81)
962  {
964  }
965  if(SpeedTag == 82)
966  {
968  }
969  if(SpeedTag == 83)
970  {
972  }
973  if(SpeedTag == 84)
974  {
976  }
977  if(SpeedTag == 85)
978  {
980  }
981  if(SpeedTag == 86)
982  {
984  }
985  if(SpeedTag == 87)
986  {
988  }
989  if(SpeedTag == 129)
990  {
991  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
992 
993  }
994  if(SpeedTag == 130)
995  {
997  }
998  if(XLinkPos == -1) // not set, could be first element or last element = leading point
999  {
1000 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
1001  if(Link[2] != -1)
1002  {
1003  return(0); // i.e. complex element, don't display
1004  }
1005  else
1006  {
1007  if(!EntryExitNumber())
1008  {
1009  throw Exception("Error in EntryExitNumber 7");
1010  }
1011  else
1012  {
1014  }
1015  }
1016  }
1017  if(EXNumber > 15) // underbridge
1018  {
1020  }
1021  else
1022  {
1024  }
1025 }
1026 
1027 // ---------------------------------------------------------------------------
1028 
1030 /*
1031  Get PrefDir direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1032 */
1033 {
1034  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1035  {
1037  }
1038  else
1039  {
1040  throw Exception("Error in EntryExitNumber 8");
1041  }
1042 }
1043 
1044 // ---------------------------------------------------------------------------
1045 
1046 Graphics::TBitmap *TPrefDirElement::GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
1047 /*
1048  Get route direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1049 */
1050 {
1051  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1052  {
1053  if(!AutoSigsFlag && !PrefDirRoute)
1054  {
1056  }
1057  else if(!AutoSigsFlag && PrefDirRoute)
1058  {
1060  }
1061  else
1062  {
1064  }
1065  }
1066  else
1067  {
1068  throw Exception("Error in EntryExitNumber 9");
1069  }
1070 }
1071 
1072 // ---------------------------------------------------------------------------
1073 
1075 /*
1076  Set == operator when TrackVectorPosition, ELink & XLink all same
1077 */
1078 {
1079  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1080  {
1081  return(true);
1082  }
1083  else
1084  {
1085  return(false);
1086  }
1087 }
1088 
1089 // ---------------------------------------------------------------------------
1090 
1092 /*
1093  Set != operator when any of TrackVectorPosition, ELink or XLink different
1094 */
1095 {
1096  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1097  {
1098  return(false);
1099  }
1100  else
1101  {
1102  return(true);
1103  }
1104 }
1105 
1106 // ---------------------------------------------------------------------------
1107 // Track functions
1108 // ---------------------------------------------------------------------------
1109 
1110 // ---------------------------------------------------------------------------
1111 
1112 TTrack::TActiveLevelCrossing::TActiveLevelCrossing()
1113 {
1114  TypeOfRoute = 0;
1115  ReducedTimePenalty = false;
1116  BarrierState = Up;
1117  ChangeDuration = 0.0;
1118  BaseElementSpeedTag = 1;
1119  HLoc = 0;
1120  VLoc = 0;
1121  StartTime = TDateTime(0);
1122 }
1123 
1124 // ---------------------------------------------------------------------------
1125 
1127 {
1128 // CurrentSpeedButtonTag = 0; //not assigned yet
1129 
1130  HLocMin = 2000000000;
1131  VLocMin = 2000000000;
1132  HLocMax = -2000000000;
1133  VLocMax = -2000000000;
1134  SkipLocationNameMultiMapCheck = false; // new at v2.2.0, false is default value
1135  CopyFlag = false; // only true for copying, so names aren't copied
1136  AnsiString NL = '\n';
1137 
1138  RouteFailMessage = "Unable to set a route:" + NL + NL + "it may be unreachable, perhaps because of failed points; " + NL + NL +
1139  "reachable but with too many different directions leading away from the start point - set some points on the route required; " + NL + NL +
1140  "blocked by a train, another route or a changing level crossing; " + NL + NL +
1141  "or invalid - possibly due to a preferred direction mismatch, or a missed signal in a blue route or green route restricted to consecutive signals.";
1142 
1147 
1148  int InternalLinkCheckArray[9][2] =
1149  {{1, 9}, {4, 6}, {7, 3}, {2, 8}, {0, 0}, {8, 2}, {3, 7}, {6, 4}, {9, 1}};
1150 
1151 /* array of valid link values for 'old' location and 'new' location, where
1152  array number = (((Hnew - Hold)+1)*3) + ((Vnew - Vold)+1) */
1153 
1154  for(int x = 0; x < 9; x++)
1155  {
1156  for(int y = 0; y < 2; y++)
1157  {
1158  LinkCheckArray[x][y] = InternalLinkCheckArray[x][y];
1159  }
1160  }
1161 
1162 // Platform and default track element values
1163  TopPlatAllowed << 1 << 9 << 10 << 30 << 31 << 60 << 61 << 68 << 69 << 77 << 125 << 126 << 129 << 145;
1164 // top & bot sigs, straights, straight points, buffers, signal, vert footcrossing, bot plat
1165  BotPlatAllowed << 1 << 7 << 8 << 28 << 29 << 60 << 61 << 68 << 69 << 76 << 125 << 126 << 129 << 145;
1166  LeftPlatAllowed << 2 << 12 << 14 << 33 << 35 << 62 << 63 << 70 << 71 << 79 << 127 << 128 << 130 << 146;
1167  RightPlatAllowed << 2 << 11 << 13 << 32 << 34 << 62 << 63 << 70 << 71 << 78 << 127 << 128 << 130 << 146;
1168  NameAllowed << 1 << 2 << 3 << 4 << 5 << 6 << 20 << 21 << 22 << 23 << 24 << 25 << 26 << 27 // disallow diagonals, points, crossovers, bridges, gaps,
1169  << 60 << 61 << 62 << 63 << 68 << 69 << 70 << 71 << 80 << 81 << 82 << 83 << 125 << 126 << 127 << 128; // diag continuations, diag buffers, footcrossings (diagonals may be OK
1170  // but as can't link diagonal locations would need solid blocks to allow linkage & that would look untidy except for single
1171  // elements, & can always use straights so leave out.) Allow horiz & vert signals as from v2.6.0
1172  LevelCrossingAllowed << 1 << 2; // only allow on straight tracks without direction markers
1173 // Note platforms not allowed at continuations, but named non-station locations OK, though not allowed in timetables
1174 
1175  int HVArray[10][2] =
1176  {{0, 0}, {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {0, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};
1177 
1178  for(int x = 0; x < 10; x++)
1179  {
1180  for(int y = 0; y < 2; y++)
1181  {
1182  LinkHVArray[x][y] = HVArray[x][y];
1183  }
1184  }
1185  TrackFinished = false;
1186 // DistancesSet = false;
1187 
1188  TSigElement TempSigTable[40] = // original four aspect
1189  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1190  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1191 
1192  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1193  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1194 
1197 
1198  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1199  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1200 
1201  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1202  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1203  {75, 4, RailGraphics->gl75}};
1204 
1205  for(int x = 0; x < 40; x++)
1206  {
1207  SigTable[x] = TempSigTable[x];
1208  }
1209 
1210  TSigElement TempSigTableThreeAspect[40] =
1211  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1212  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1213 
1214  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1215  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1216 
1217  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1218  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1219 
1220  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1221  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1222 
1223  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1224  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1225  {75, 4, RailGraphics->gl75}};
1226 
1227  for(int x = 0; x < 40; x++)
1228  {
1229  SigTableThreeAspect[x] = TempSigTableThreeAspect[x];
1230  }
1231 
1232  TSigElement TempSigTableTwoAspect[40] =
1233  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1234  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1235 
1236  {68, 1, RailGraphics->bm68green}, {69, 1, RailGraphics->bm69green}, {70, 1, RailGraphics->bm70green}, {71, 1, RailGraphics->bm71green},
1237  {72, 1, RailGraphics->bm72green}, {73, 1, RailGraphics->bm73green}, {74, 1, RailGraphics->bm74green}, {75, 1, RailGraphics->bm75green},
1238 
1239  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1240  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1241 
1242  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1243  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1244 
1245  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1246  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1247  {75, 4, RailGraphics->gl75}};
1248 
1249  for(int x = 0; x < 40; x++)
1250  {
1251  SigTableTwoAspect[x] = TempSigTableTwoAspect[x];
1252  }
1253 
1254  TSigElement TempSigTableGroundSignal[40] =
1258 
1262 
1266 
1270 
1271  {68, 4, RailGraphics->bm68grounddblred}, {69, 4, RailGraphics->bm69grounddblred}, // Attr 4 disused but leave in case re-instate
1274 
1275  for(int x = 0; x < 40; x++)
1276  {
1277  SigTableGroundSignal[x] = TempSigTableGroundSignal[x];
1278  }
1279 
1280  TSigElement TempFailedSigTable[8] = // added at v2.13.0
1281  {{68, 0, RailGraphics->FSig68}, {69, 0, RailGraphics->FSig69}, {70, 0, RailGraphics->FSig70}, {71, 0, RailGraphics->FSig71}, {72, 0, RailGraphics->FSig72},
1282  {73, 0, RailGraphics->FSig73}, {74, 0, RailGraphics->FSig74}, {75, 0, RailGraphics->FSig75}};
1283 
1284  for(int x = 0; x < 8; x++)
1285  {
1286  FailedSigTable[x] = TempFailedSigTable[x];
1287  }
1288 
1289 /*
1290  Named Location Arrays: Set out the adjacent positions and tracktypes that are accepted as valid connections for
1291  a single location. These are as follows:-
1292  Directly Adjacent = up, down, left or right - NOT diagonal.
1293  There are two separate groups, platforms, concourses & footcrossings (providing the crossing part touches or overlaps the other relevant
1294  named location) all link with each other providing directly adjacent, but not to NamedNonStationLocations.
1295  NamedNonStationLocation link to other NamedNonStationLocations providing directly adjacent, but not to anything else.
1296 
1297  //t 76
1298  //b 77
1299  //l 78
1300  //r 79
1301  //c 96
1302  //v fb 129
1303  //h fb 130
1304  //v underpass 145
1305  //h underpass 146
1306  //n 131
1307 */
1308 
1309  int Tag76[25][3] =
1310  {{-1, 0, 96}, // c top plat
1311  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1312  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1313  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {0, 0, 77}, {-1, 0, 78}, // l
1314  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1315  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, -1, 129}, // v fb
1316  {0, 0, 129}, {0, -1, 145}, // v up
1317  {0, 0, 145}};
1318 
1319  for(int x = 0; x < 25; x++)
1320  {
1321  for(int y = 0; y < 3; y++)
1322  {
1323  Tag76Array[x][y] = Tag76[x][y];
1324  }
1325  }
1326 
1327  int Tag77[25][3] =
1328  {{-1, 0, 96}, // c bot plat
1329  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1330  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {0, 0, 76}, {-1, 0, 77}, // b
1331  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1332  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1333  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1334  {0, 0, 129}, {0, 1, 145}, // v up
1335  {0, 0, 145}};
1336 
1337  for(int x = 0; x < 25; x++)
1338  {
1339  for(int y = 0; y < 3; y++)
1340  {
1341  Tag77Array[x][y] = Tag77[x][y];
1342  }
1343  }
1344 
1345  int Tag78[25][3] =
1346  {{-1, 0, 96}, // c left plat
1347  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1348  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1349  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1350  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1351  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 0, 79}, {-1, 0, 130}, // h fb
1352  {0, 0, 130}, {-1, 0, 146}, // h up
1353  {0, 0, 146}};
1354 
1355  for(int x = 0; x < 25; x++)
1356  {
1357  for(int y = 0; y < 3; y++)
1358  {
1359  Tag78Array[x][y] = Tag78[x][y];
1360  }
1361  }
1362 
1363  int Tag79[25][3] =
1364  {{-1, 0, 96}, // c right plat
1365  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1366  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1367  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1368  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {0, 0, 78}, {-1, 0, 79}, // r
1369  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {1, 0, 130}, // h fb
1370  {0, 0, 130}, {1, 0, 146}, // h up
1371  {0, 0, 146}};
1372 
1373  for(int x = 0; x < 25; x++)
1374  {
1375  for(int y = 0; y < 3; y++)
1376  {
1377  Tag79Array[x][y] = Tag79[x][y];
1378  }
1379  }
1380 
1381  int Tag96[28][3] =
1382  {{-1, 0, 96}, // c //concourse
1383  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1384  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1385  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1386  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1387  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1388  {0, -1, 129}, {1, 0, 130}, // h fb
1389  {-1, 0, 130}, {0, 1, 145}, // v up
1390  {0, -1, 145}, {1, 0, 146}, // h up
1391  {-1, 0, 146}};
1392 
1393  for(int x = 0; x < 28; x++)
1394  {
1395  for(int y = 0; y < 3; y++)
1396  {
1397  Tag96Array[x][y] = Tag96[x][y];
1398  }
1399  }
1400 
1401  int Tag129[8][3] = // vert fb
1402  {{0, -1, 96}, // c
1403  {0, -1, 77}, // b
1404  {0, -1, 129}, // v fb
1405 
1406  {0, 1, 96}, // c
1407  {0, 1, 76}, // t
1408  {0, 1, 129}, // v fb
1409 
1410  {0, 0, 76}, // t
1411  {0, 0, 77}}; // b
1412 
1413  for(int x = 0; x < 8; x++)
1414  {
1415  for(int y = 0; y < 3; y++)
1416  {
1417  Tag129Array[x][y] = Tag129[x][y];
1418  }
1419  }
1420 
1421  int Tag145[8][3] = // vert up
1422  {{0, -1, 96}, // c
1423  {0, -1, 77}, // b
1424  {0, -1, 145}, // v fb
1425 
1426  {0, 1, 96}, // c
1427  {0, 1, 76}, // t
1428  {0, 1, 145}, // v fb
1429 
1430  {0, 0, 76}, // t
1431  {0, 0, 77}}; // b
1432 
1433  for(int x = 0; x < 8; x++)
1434  {
1435  for(int y = 0; y < 3; y++)
1436  {
1437  Tag145Array[x][y] = Tag145[x][y];
1438  }
1439  }
1440 
1441  int Tag130[8][3] = // hor fb
1442  {{-1, 0, 96}, // c
1443  {-1, 0, 79}, // r
1444  {-1, 0, 130}, // h fb
1445 
1446  {1, 0, 96}, // c
1447  {1, 0, 78}, // l
1448  {1, 0, 130}, // h fb
1449 
1450  {0, 0, 78}, // l
1451  {0, 0, 79}}; // r
1452 
1453  for(int x = 0; x < 8; x++)
1454  {
1455  for(int y = 0; y < 3; y++)
1456  {
1457  Tag130Array[x][y] = Tag130[x][y];
1458  }
1459  }
1460 
1461  int Tag146[8][3] = // hor up
1462  {{-1, 0, 96}, // c
1463  {-1, 0, 79}, // r
1464  {-1, 0, 146}, // h fb
1465 
1466  {1, 0, 96}, // c
1467  {1, 0, 78}, // l
1468  {1, 0, 146}, // h fb
1469 
1470  {0, 0, 78}, // l
1471  {0, 0, 79}}; // r
1472 
1473  for(int x = 0; x < 8; x++)
1474  {
1475  for(int y = 0; y < 3; y++)
1476  {
1477  Tag146Array[x][y] = Tag146[x][y];
1478  }
1479  }
1480 
1481  int Tag131[4][3] =
1482  {{-1, 0, 131}, // n
1483  {1, 0, 131}, {0, -1, 131}, {0, 1, 131}};
1484 
1485  for(int x = 0; x < 4; x++)
1486  {
1487  for(int y = 0; y < 3; y++)
1488  {
1489  Tag131Array[x][y] = Tag131[x][y];
1490  }
1491  }
1492 
1493  int InternalFlipArray[FirstUnusedSpeedTagNumber] =
1494  {
1495  0, 1, 2, 5, 6, 3, 4, 9, 10, 7, 8, 13, 14, 11, 12, 15, 16, 17, 19, 18, 22, 23, 20, 21, 26, 27, 24, 25, 30, 31, 28, 29, 34, 35, 32, 33, 38, 39, 36, 37, 42,
1496  43, 40, 41, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 60, 61, 63, 62, 66, 67, 64, 65, 68, 69, 71, 70, 74, 75, 72, 73, 77, 76, 78,
1497  79, 80, 81, 83, 82, 86, 87, 84, 85, 88, 89, 91, 90, 94, 95, 92, 93, 96, 99, 100, 97, 98, 103, 104, 101, 102, 106, 105, 109, 110, 107, 108, 113, 114,
1498  111, 112, 117, 118, 115, 116, 119, 120, 121, 123, 122, 124, 125, 126, 128, 127, 129, 130, 131, 134, 133, 132, 135, 139, 138, 137, 136, 143, 142, 141,
1499  140, 144, 145, 146
1500  };
1501 
1502  int InternalMirrorArray[FirstUnusedSpeedTagNumber] =
1503  {
1504  0, 1, 2, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 15, 16, 17, 19, 18, 21, 20, 23, 22, 25, 24, 27, 26, 29, 28, 31, 30, 33, 32, 35, 34, 37, 36, 39, 38, 41,
1505  40, 43, 42, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 61, 60, 62, 63, 65, 64, 67, 66, 69, 68, 70, 71, 73, 72, 75, 74, 76, 77, 79,
1506  78, 81, 80, 82, 83, 85, 84, 87, 86, 89, 88, 90, 91, 93, 92, 95, 94, 96, 98, 97, 100, 99, 102, 101, 104, 103, 106, 105, 108, 107, 110, 109, 112, 111,
1507  114, 113, 116, 115, 118, 117, 119, 120, 124, 122, 123, 121, 126, 125, 127, 128, 129, 130, 131, 132, 135, 134, 133, 137, 136, 139, 138, 142, 143, 140,
1508  141, 144, 145, 146
1509  };
1510 
1511  int InternalRotRightArray[FirstUnusedSpeedTagNumber] =
1512  {
1513  0, 2, 1, 4, 6, 3, 5, 14, 12, 13, 11, 7, 9, 8, 10, 15, 16, 17, 19, 18, 25, 27, 24, 26, 21, 23, 20, 22, 35, 33, 34, 32, 28, 30, 29, 31, 41, 43, 40, 42, 37,
1514  39, 36, 38, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 63, 62, 60, 61, 65, 67, 64, 66, 71, 70, 68, 69, 73, 75, 72, 74, 79, 78, 76,
1515  77, 83, 82, 80, 81, 85, 87, 84, 86, 91, 90, 88, 89, 93, 95, 92, 94, 96, 102, 104, 101, 103, 98, 100, 97, 99, 106, 105, 108, 110, 107, 109, 116, 118,
1516  115, 117, 112, 114, 111, 113, 120, 119, 122, 124, 121, 123, 127, 128, 126, 125, 130, 129, 131, 133, 134, 135, 132, 137, 138, 139, 136, 143, 142, 140,
1517  141, 144, 146, 145
1518  };
1519 
1520  int InternalRotLeftArray[FirstUnusedSpeedTagNumber] =
1521  {
1522  0, 2, 1, 5, 3, 6, 4, 11, 13, 12, 14, 10, 8, 9, 7, 15, 16, 17, 19, 18, 26, 24, 27, 25, 22, 20, 23, 21, 32, 34, 33, 35, 31, 29, 30, 28, 42, 40, 43, 41, 38,
1523  36, 39, 37, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 62, 63, 61, 60, 66, 64, 67, 65, 70, 71, 69, 68, 74, 72, 75, 73, 78, 79, 77,
1524  76, 82, 83, 81, 80, 86, 84, 87, 85, 90, 91, 89, 88, 94, 92, 95, 93, 96, 103, 101, 104, 102, 99, 97, 100, 98, 106, 105, 109, 107, 110, 108, 117, 115,
1525  118, 116, 113, 111, 114, 112, 120, 119, 123, 121, 124, 122, 128, 127, 125, 126, 130, 129, 131, 135, 132, 133, 134, 139, 136, 137, 138, 142, 143, 141,
1526  140, 144, 146, 145
1527  };
1528 
1529  for(int x = 0; x < FirstUnusedSpeedTagNumber; x++)
1530  {
1531  FlipArray[x] = InternalFlipArray[x];
1532  MirrorArray[x] = InternalMirrorArray[x];
1533  RotRightArray[x] = InternalRotRightArray[x];
1534  RotLeftArray[x] = InternalRotLeftArray[x];
1535  }
1536 }
1537 
1538 // ---------------------------------------------------------------------------
1540 {
1541 // delete TrackVectorPtr;
1542 // delete FixedTrackArrayPtr;
1543  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1544 
1545  while(UGMIt != Track->UserGraphicMap.end()) // delete all the TPictures in the map
1546  {
1547  delete UGMIt->second;
1548  UGMIt++;
1549  }
1550  delete GapFlashGreen;
1551  delete GapFlashRed;
1552  // all the rest are cleared by the relevant automatic destructors
1553 }
1554 
1555 // ---------------------------------------------------------------------------
1556 
1558 {
1559  Graphics::TBitmap *TrackImageArray[FirstUnusedSpeedTagNumber] =
1560  {
1561 // loc 0 not used, set to bmSolidBgnd
1565 // no 17 not used (was used for text in early phases), set to bmSolidBgnd
1585  };
1586 
1587  Graphics::TBitmap *SmallTrackImageArray[FirstUnusedSpeedTagNumber] =
1588  {
1589 // loc 0 not used, set to smSolidBgnd
1593 // no 17 not used (was used for text in early phases), set to smSolidBgnd
1612  RailGraphics->smLC, RailGraphics->sm129, RailGraphics->sm130 // use small footbridges for underpasses
1613  };
1614 
1615 // track types
1616  TTrackType TrackTypeArray[FirstUnusedSpeedTagNumber] =
1617  {
1618  Erase, // 1 0
1619  Simple, Simple, Simple, Simple, Simple, Simple, // 6 1-6
1620  Points, Points, Points, Points, Points, Points, Points, Points, // 8 7-14
1621  Crossover, Crossover, // 2 15-16
1622  Unused, // 17 (was for text in earlier development) //1 17
1625  Crossover, Crossover, Crossover, Crossover, // 4 44-47
1629  Platform, Platform, Platform, Platform, // 4 76-79
1632  Concourse, // 1 96
1635  Simple, Simple, Simple, Simple, // 4 125-128
1636  FootCrossing, FootCrossing, // 2 129-130
1637  NamedNonStationLocation, // 1 131
1638  Points, Points, Points, Points, Points, Points, Points, Points, // 8 132-139
1639  Simple, Simple, Simple, Simple, // 4 140-143
1640  LevelCrossing, // 1 144
1641  FootCrossing, FootCrossing // 2 145 & 146
1642  };
1643 
1644 // links
1645  int Links[FirstUnusedSpeedTagNumber][4] =
1646  {{-1, -1, -1, -1}, // erase element
1647  {4, 6, -1, -1}, {2, 8, -1, -1}, {6, 8, -1, -1}, {4, 8, -1, -1}, {2, 6, -1, -1}, {2, 4, -1, -1}, // simple
1648  {4, 6, 4, 2}, {6, 4, 6, 2}, {4, 6, 4, 8}, {6, 4, 6, 8}, {8, 2, 8, 4}, {8, 2, 8, 6}, {2, 8, 2, 4}, {2, 8, 2, 6}, // points
1649 // points always have links 0 & 2 = lead, link 1 = trailing straight, link 3 = trailing diverging
1650  {4, 6, 2, 8}, {1, 9, 3, 7}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1651  {-1, -1, -1, -1}, // unused
1652  {3, 7, -1, -1}, {1, 9, -1, -1}, {7, 6, -1, -1}, {4, 9, -1, -1}, {1, 6, -1, -1}, {4, 3, -1, -1}, {3, 8, -1, -1}, {1, 8, -1, -1}, {2, 9, -1, -1},
1653  {2, 7, -1, -1}, // simple
1654  {4, 6, 4, 3}, {6, 4, 6, 1}, {4, 6, 4, 9}, {6, 4, 6, 7}, {8, 2, 8, 1}, {8, 2, 8, 3}, {2, 8, 2, 7}, {2, 8, 2, 9}, {9, 1, 9, 2}, {7, 3, 7, 2}, {3, 7, 3, 8}, {1, 9, 1, 8}, {9, 1, 9, 4}, {7, 3, 7, 6}, {3, 7, 3, 4}, {1, 9, 1, 6}, // points
1655 // points always have links 0 & 2 = lead, link 1 = trailing straight (or left diverging if no straight), link 3 = trailing diverging
1656 // (or right diverging if no straight)
1657  {1, 9, 2, 8}, {2, 8, 3, 7}, {4, 6, 3, 7}, {1, 9, 4, 6}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1658  {2, 8, 4, 6}, {4, 6, 2, 8}, {3, 7, 1, 9}, {1, 9, 3, 7}, {2, 8, 1, 9}, {2, 8, 3, 7}, {3, 7, 2, 8}, {1, 9, 2, 8}, {4, 6, 3, 7}, {4, 6, 1, 9}, {1, 9, 4, 6}, {3, 7, 4, 6}, // bridge, links 2 & 3 = underbridge
1659  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // buffers - position 0 = buffer
1660  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, // signals (need Config to determine signal end, see below)
1661  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // platform
1662  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // continuation - position 0 = continuation
1663  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // gapjump - position 0 = gap
1664  {-1, -1, -1, -1}, // Concourse
1665  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1666  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1667  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1668  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // Parapets
1669  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, // arrows
1670  {4, 6, -1, -1}, {2, 8, -1, -1}, // footbridges
1671  {-1, -1, -1, -1}, // NamedNonStationLocation
1672  {8, 1, 8, 3}, {4, 3, 4, 9}, {2, 9, 2, 7}, {6, 7, 6, 1}, {9, 4, 9, 2}, {7, 2, 7, 6}, {1, 6, 1, 8}, {3, 8, 3, 4}, // points without straight legs
1673 // these points have links 0 & 2 = lead, link 1 = LH trailing, link 3 = RH trailing
1674  {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, {1, 9, -1, -1}, // arrowed diagonals
1675  {-1, -1, -1, -1}, // level crossing
1676  {4, 6, -1, -1}, {2, 8, -1, -1}, // underpasses/surface crossings
1677  };
1678 
1680  {{NotSet, NotSet, NotSet, NotSet}, // unused
1684  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1686  {NotSet, NotSet, NotSet, NotSet}, // unused
1690  {Connection, Connection, NotSet, NotSet}, // simple
1694  {Lead, Trail, Lead, Trail}, // points
1696  {CrossConn, CrossConn, CrossConn, CrossConn}, // crossover
1704  {Signal, Connection, NotSet, NotSet}, {Signal, Connection, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, // signals (signal at exit end in forward direction)
1710  {NotSet, NotSet, NotSet, NotSet}, // Concourse
1719  {Connection, Connection, NotSet, NotSet}, // Arrows
1721  {NotSet, NotSet, NotSet, NotSet}, // NamedNonStationLocation
1723  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1725  {Connection, Connection, NotSet, NotSet}, // Arrowed diagonals
1726  {NotSet, NotSet, NotSet, NotSet}, // Level crossing
1727  {Connection, Connection, NotSet, NotSet}, {Connection, Connection, NotSet, NotSet} // Underpasses/surface crossings
1728  };
1729 
1730  for(int x = 0; x < 17; x++)
1731  {
1732  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1733  }
1734  FixedTrackPiece[17] = TFixedTrackPiece(17, TrackTypeArray[17], Links[17], Configs[17], 0, 0);
1735 // 17 was the old text value so don't want any graphics (now disused)
1736  for(int x = 18; x < FirstUnusedSpeedTagNumber; x++)
1737  {
1738  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1739  }
1740 }
1741 
1742 // ---------------------------------------------------------------------------
1743 TGraphicElement::TGraphicElement() : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1744  ExistingGraphicLoaded(false), Width(16), Height(16)
1745 {
1746  OriginalGraphic = new Graphics::TBitmap;
1747  OriginalGraphic->PixelFormat = pf8bit;
1748  OriginalGraphic->Width = Width;
1749  OriginalGraphic->Height = Height;
1750  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1751 }
1752 
1753 // ---------------------------------------------------------------------------
1754 
1755 TGraphicElement::TGraphicElement(int WidthIn, int HeightIn) : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1756  ExistingGraphicLoaded(false), Width(WidthIn), Height(HeightIn)
1757 {
1758  OriginalGraphic = new Graphics::TBitmap;
1759  OriginalGraphic->PixelFormat = pf8bit;
1760  OriginalGraphic->Width = Width;
1761  OriginalGraphic->Height = Height;
1762  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1763 }
1764 
1765 // ---------------------------------------------------------------------------
1766 
1768 {
1769  delete OriginalGraphic;
1770 }
1771 
1772 // ---------------------------------------------------------------------------
1773 
1774 void TGraphicElement::SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
1775 {
1776  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetScreenHVSource," + AnsiString(HPosIn) + "," + AnsiString(VPosIn));
1777  HPos = HPosIn; // HPos & VPos are members of TGraphicElement
1778  VPos = VPosIn;
1779  int Left, Top; // can't use e.g. PointFlash.SourceRect.Left & Top directly as references as don't exist as objects in their own right
1780 
1781  Track->GetScreenPositionsFromTruePos(2, Left, Top, HPos, VPos);
1782  SourceRect.init(Left, Top, Left + Width, Top + Height);
1783  ScreenSourceSet = true;
1784  Utilities->CallLogPop(422);
1785 }
1786 
1787 // ---------------------------------------------------------------------------
1788 
1790 {
1791  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalScreenGraphic");
1792  if(!OverlayLoaded)
1793  {
1794  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalScreenGraphic()");
1795  }
1796  if((OverlayGraphic->Width != 16) || (OverlayGraphic->Height != 16))
1797  {
1798  throw Exception("Overlay not 16x16 in TGraphicElement::LoadOriginalScreenGraphic()");
1799  }
1800  if(!ScreenSourceSet)
1801  {
1802  throw Exception("Source not set in TGraphicElement::LoadOriginalScreenGraphic()");
1803  }
1804  if(ExistingGraphicLoaded) // can only call one of the load functions
1805  {
1806  throw Exception("ExistingGraphicLoaded in TGraphicElement::LoadOriginalScreenGraphic()");
1807  }
1808  if(OverlayPlotted) // don't load from screen if overlay plotted
1809  {
1810  Utilities->CallLogPop(775);
1811  return;
1812  }
1813  TRect DestRect(0, 0, Width, Height);
1814 
1816  OriginalLoaded = true;
1817  ScreenGraphicLoaded = true;
1818  Utilities->CallLogPop(423);
1819 }
1820 
1821 // ---------------------------------------------------------------------------
1822 
1823 void TGraphicElement::LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
1824 /*
1825  Overrides size set in the constructor, SourceRect & HPos & VPos in SetScreenHVSource
1826 */
1827 {
1828  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalExistingGraphic," + AnsiString(HOffset) + "," +
1829  AnsiString(VOffset) + "," + AnsiString(WidthIn) + "," + AnsiString(HeightIn));
1830  if(!OverlayLoaded)
1831  {
1832  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalExistingGraphic()");
1833  }
1834  if(!ScreenSourceSet) // has to be called to set HPos & VPos
1835  {
1836  throw Exception("Source not set in TGraphicElement::LoadOriginalExistingGraphic()");
1837  }
1838  if(ScreenGraphicLoaded) // can only call one of the load functions
1839  {
1840  throw Exception("ScreenGraphicLoaded in TGraphicElement::LoadOriginalExistingGraphic()");
1841  }
1842  Width = WidthIn;
1843  Height = HeightIn;
1844  OriginalGraphic->Width = Width;
1845  OriginalGraphic->Height = Height;
1846  HPos += HOffset; // originally set in SetScreenHVSource to position of H & V locations
1847  VPos += VOffset;
1848  TRect DestRect(0, 0, Width, Height);
1849 
1850  SourceRect.init(HOffset, VOffset, HOffset + Width, VOffset + Height);
1851  OriginalGraphic->Canvas->CopyRect(DestRect, Graphic->Canvas, SourceRect);
1852  OriginalLoaded = true;
1853  ExistingGraphicLoaded = true;
1854  Utilities->CallLogPop(424);
1855 }
1856 
1857 // ---------------------------------------------------------------------------
1858 
1859 void TGraphicElement::LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
1860 {
1861  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOverlayGraphic,");
1862  OverlayGraphic = Overlay;
1863  OverlayLoaded = true;
1864  Utilities->CallLogPop(425);
1865 }
1866 
1867 // ---------------------------------------------------------------------------
1868 
1870 {
1871  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOverlay,");
1872  if(!OverlayLoaded)
1873  {
1874  throw Exception("Overlay not loaded in TGraphicElement::PlotOverlay()");
1875  }
1876  if(!OverlayPlotted)
1877  {
1878  Disp->PlotOutput(35, HPos, VPos, OverlayGraphic); // plot overlay
1879  Disp->Update();
1880  OverlayPlotted = true;
1881  }
1882  Utilities->CallLogPop(426);
1883 }
1884 
1885 // ---------------------------------------------------------------------------
1886 
1888 {
1889  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOriginal,");
1890  if(OverlayPlotted)
1891  {
1892  if(!OriginalLoaded) // this comes after OverlayPlotted because may wish to 'try' to plot original even
1893  // when it isn't loaded in case it had been plotted - e.g. when change user modes
1894  {
1895  throw Exception("Original not loaded in TGraphicElement::PlotOriginal()");
1896  }
1897  Disp->PlotOutput(36, HPos, VPos, OriginalGraphic); // replot original
1898  Disp->Update(); // This was commented out originally but when in flashes much less frequent when points changing manually
1899  OverlayPlotted = false;
1900  }
1901  Utilities->CallLogPop(427);
1902 }
1903 
1904 // ---------------------------------------------------------------------------
1905 
1907 {
1908  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoTrack");
1909  bool TrackPresent = false;
1910 
1911  if(InactiveTrackVector.size() != 0)
1912  {
1913  Utilities->CallLogPop(1333);
1914  return(false);
1915  }
1916  else if(TrackVector.size() == 0)
1917  {
1918  Utilities->CallLogPop(1334);
1919  return(true);
1920  }
1921  else
1922  {
1923  for(unsigned int x = 0; x < TrackVector.size(); x++)
1924  {
1925  if((TrackElementAt(1042, x).SpeedTag != 0))
1926  {
1927  TrackPresent = true;
1928  }
1929  }
1930  }
1931  Utilities->CallLogPop(1335);
1932  return(!TrackPresent);
1933 }
1934 
1935 // ---------------------------------------------------------------------------
1936 
1937 bool TTrack::NoActiveTrack(int Caller)
1938 {
1939  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoActiveTrack");
1940  bool TrackPresent = false;
1941 
1942  if(TrackVector.size() == 0)
1943  {
1944  Utilities->CallLogPop(1582);
1945  return(true);
1946  }
1947  else
1948  {
1949  for(unsigned int x = 0; x < TrackVector.size(); x++)
1950  {
1951  if((TrackElementAt(1043, x).SpeedTag != 0))
1952  {
1953  TrackPresent = true;
1954  }
1955  break;
1956  }
1957  }
1958  Utilities->CallLogPop(1583);
1959  return(!TrackPresent);
1960 }
1961 
1962 // ---------------------------------------------------------------------------
1963 
1964 void TTrack::EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
1965 {
1966  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseTrackElement," + AnsiString(HLocInput) + "," +
1967  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
1968  TrackEraseSuccessfulFlag = false;
1969 // TrackEraseSuccessfulFlag used for both track element and inactive element erase,
1970 // since have to match platforms as well as track
1971 // used to set TrackFinished to false if an element erased
1972 
1973  ErasedTrackVectorPosition = -1; // marker for no element erased
1974  AnsiString SName = "", ErrorString;
1976  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
1977  TTrackMapIterator TrackMapPtr;
1978  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
1979 
1980  if(TrackVector.size() != 0)
1981  {
1982  TrackMapKeyPair.first = HLocInput;
1983  TrackMapKeyPair.second = VLocInput;
1984  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
1985  if(TrackMapPtr != TrackMap.end())
1986  {
1987  bool FoundFlag;
1988  int VecPos = GetVectorPositionFromTrackMap(37, HLocInput, VLocInput, FoundFlag);
1989  if(FoundFlag) // should find it as it's in the map
1990  {
1991  if(TrackElementAt(629, VecPos).FixedNamedLocationElement) // footcrossings only
1992  {
1993  SName = TrackElementAt(1, VecPos).LocationName;
1994  SNIt = FindNamedElementInLocationNameMultiMap(7, SName, TrackVector.begin() + VecPos, ErrorString);
1995  if(ErrorString != "")
1996  {
1997  throw Exception(ErrorString + " for EraseTrackElement 1");
1998  }
1999  LocationNameMultiMap.erase(SNIt);
2000  }
2001  TrackVector.erase(TrackVector.begin() + TrackMapPtr->second);
2002  // ensure erase vector element before map element as iterator no longer valid after a map erase
2003  TrackMap.erase(TrackMapPtr);
2004  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(2, HLocInput, VLocInput); // plot a blank element
2005  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2007  ResetAnyNonMatchingGaps(1); // in case the deleted element was a set gap
2008  if(SName != "")
2009  {
2010  EraseLocationAndActiveTrackElementNames(5, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2011  int HPos, VPos;
2012  if(TextHandler->FindText(1, SName, HPos, VPos))
2013  {
2014  if(TextHandler->TextErase(5, HPos, VPos, SName))
2015  {
2016  ;
2017  } // condition not used
2018 
2019  }
2020  }
2021  ErasedTrackVectorPosition = VecPos;
2022  TrackEraseSuccessfulFlag = true;
2023  }
2024  }
2025  }
2026  if(InactiveTrackVector.size() != 0)
2027  {
2028  unsigned int VecPos;
2029  InactiveTrackMapKeyPair.first = HLocInput;
2030  InactiveTrackMapKeyPair.second = VLocInput;
2031  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair);
2032  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2033  {
2034  SName = "";
2035  VecPos = InactiveTrack2MultiMapIterator->second;
2036  if(InactiveTrackElementAt(0, VecPos).FixedNamedLocationElement)
2037  {
2038  SName = InactiveTrackElementAt(1, VecPos).LocationName;
2039  SNIt = FindNamedElementInLocationNameMultiMap(2, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2040  if(ErrorString != "")
2041  {
2042  throw Exception(ErrorString + " for EraseTrackElement 2A");
2043  }
2044  LocationNameMultiMap.erase(SNIt);
2045  }
2046  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2047  // ensure erase vector element before map element as iterator no longer valid after a map erase
2048  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2049  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(1, HLocInput, VLocInput); // plot a blank element
2050  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2052  TrackEraseSuccessfulFlag = true;
2053  if(SName != "")
2054  {
2055  EraseLocationAndActiveTrackElementNames(3, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2056  int HPos, VPos;
2057  if(TextHandler->FindText(2, SName, HPos, VPos))
2058  {
2059  if(TextHandler->TextErase(6, HPos, VPos, SName))
2060  {
2061  ;
2062  } // condition not used
2063 
2064  }
2065  }
2066  }
2067  if(InactiveTrackVector.size() != 0) // need to check again as last access may have erased the last element
2068  {
2069  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // may be up to 2 elements (platforms) at same location
2070  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2071  {
2072  SName = "";
2073  VecPos = InactiveTrack2MultiMapIterator->second;
2074  if(InactiveTrackElementAt(2, VecPos).FixedNamedLocationElement)
2075  {
2076  SName = InactiveTrackElementAt(3, VecPos).LocationName;
2077  SNIt = FindNamedElementInLocationNameMultiMap(3, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2078  if(ErrorString != "")
2079  {
2080  throw Exception(ErrorString + " for EraseTrackElement 2B");
2081  }
2082  LocationNameMultiMap.erase(SNIt);
2083  }
2084  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2085  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2086  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2088  if(SName != "")
2089  {
2090  EraseLocationAndActiveTrackElementNames(4, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2091  int HPos, VPos;
2092  if(TextHandler->FindText(3, SName, HPos, VPos))
2093  {
2094  if(TextHandler->TextErase(7, HPos, VPos, SName))
2095  {
2096  ;
2097  } // condition not used
2098 
2099  }
2100  }
2101  }
2102  }
2103  }
2104  if(TrackEraseSuccessfulFlag)
2105  {
2106  CalcHLocMinEtc(2);
2107  SetTrackFinished(false);
2108  }
2109  if(InternalChecks)
2110  {
2111  CheckMapAndTrack(1); // test
2112  CheckMapAndInactiveTrack(1); // test
2113  CheckLocationNameMultiMap(6); // test
2114  }
2115  Utilities->CallLogPop(428);
2116 }
2117 
2118 // ---------------------------------------------------------------------------
2119 
2120 void TTrack::PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
2121 // TrackLinkingRequiredFlag only relates to elements that require track linking after plotting - used to set TrackFinished
2122 // to false in calling function. New at v2.2.0 new parameter 'Aspect' to ensure signals plotted with correct number of aspects (for pasting)
2123 // and also when zero and combined with SignalPost to indicate that adding track rather than pasting
2124 {
2125  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotAndAddTrackElement," + AnsiString(CurrentTag) + "," +
2126  AnsiString(HLocInput) + "," + AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2127  bool PlatAllowedFlag = false;
2128 
2129  TrackLinkingRequiredFlag = false;
2130 /*
2131  Not erase, that covered separately.
2132  First check if Current SpeedButton assigned, then check if a platform and only
2133  permit if an appropriate trackpiece already there & not a same platform there.
2134  - can't enter a platform without track first.
2135  Then for non-platforms, check if a track piece already present at location &
2136  reject if so.
2137 */
2138 
2139  TLocationNameMultiMapEntry LocationNameEntry;
2140 
2141  LocationNameEntry.first = "";
2142  if(CurrentTag == 0)
2143  {
2144  Utilities->CallLogPop(429);
2145  return; // not assigned yet
2146  }
2147  TTrackElement TempTrackElement(FixedTrackArray.FixedTrackPiece[CurrentTag]);
2148 
2149  TempTrackElement.HLoc = HLocInput;
2150  TempTrackElement.VLoc = VLocInput;
2151  SetElementID(1, TempTrackElement); // TempTrackElement is the one to be added
2152 // new at version 0.6 - set signal aspect depending on build mode
2153 
2154  if(TempTrackElement.TrackType == SignalPost)
2155  {
2156  if(Aspect == 0) // new at v2.2.0, '0' and SignalPost together means that track being added & not pasted, because when
2157  // pasting a SignalPost can only have values 1 to 4
2158  {
2160  {
2161  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2162  }
2164  {
2165  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2166  }
2168  {
2169  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2170  }
2171  else
2172  {
2173  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2174  }
2175  }
2176  else if(Aspect == 1)
2177  {
2178  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2179  }
2180  else if(Aspect == 2)
2181  {
2182  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2183  }
2184  else if(Aspect == 3)
2185  {
2186  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2187  }
2188  else
2189  {
2190  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2191  }
2192  }
2193  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2194  int VecPos = GetVectorPositionFromTrackMap(12, HLocInput, VLocInput, FoundFlag); // active track already there
2195  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(5, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2196  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2197 
2198  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2199  {
2201  {
2202  NonStationOrLevelCrossingPresent = true;
2203  }
2204  if(InactiveTrackElementAt(117, IMPair.first).TrackType == LevelCrossing)
2205  {
2206  NonStationOrLevelCrossingPresent = true;
2207  }
2208  if(InactiveTrackElementAt(5, IMPair.first).TrackType == Platform)
2209  {
2210  PlatformPresent = true;
2211  }
2212  // no need to check IMPair.second since if that exists it is because .first is a platform
2213  InactiveSpeedTag1 = InactiveTrackElementAt(6, IMPair.first).SpeedTag;
2214  InactiveSpeedTag2 = InactiveTrackElementAt(7, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2215  }
2216 // check platforms
2217  if(TempTrackElement.TrackType == Platform)
2218  {
2219  if(FoundFlag) // active track element already there
2220  {
2221  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2222  {
2223  ;
2224  }
2225  // same platform type already there so above keeps PlatAllowedFlag false
2226  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1044, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2227  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2228  {
2229  PlatAllowedFlag = true;
2230  }
2231  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1045, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2232  {
2233  PlatAllowedFlag = true;
2234  }
2235  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1046, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2236  {
2237  PlatAllowedFlag = true;
2238  }
2239  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1047, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2240  {
2241  PlatAllowedFlag = true;
2242  }
2243  if(PlatAllowedFlag)
2244  {
2245  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2246  TrackPush(1, TempTrackElement);
2247  SearchForAndUpdateLocationName(1, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2248  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2249  // Must be called AFTER TrackPush
2250  // No need to plot the element - Clearand ... called after this function called
2251  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2252  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2253 // drop in v2.4.0 if(TrackElementAt(2, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2254 // AnsiString(TrackElementAt(3, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2255 // TrackElementAt(4, VecPos).Length01 = DefaultTrackLength;
2256  if(InternalChecks)
2257  {
2258  CheckMapAndInactiveTrack(5); // test
2259  CheckLocationNameMultiMap(4); // test
2260  }
2261  Utilities->CallLogPop(430);
2262  return;
2263  }
2264  } // if(FoundFlag)
2265 
2266  Utilities->CallLogPop(431);
2267  return;
2268  } // if platform
2269 
2270 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2271  if(TempTrackElement.TrackType == NamedNonStationLocation)
2272  {
2273  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1048, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2274  (!FoundFlag && !InactiveFoundFlag))
2275  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2276  {
2277  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2278  TrackPush(2, TempTrackElement);
2279  SearchForAndUpdateLocationName(2, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2280  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2281  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2282  {
2283 // drop in v2.4.0 if(TrackElementAt(830, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2284 // AnsiString(TrackElementAt(831, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2285 // TrackElementAt(832, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2286  }
2287  if(InternalChecks)
2288  {
2289  CheckMapAndInactiveTrack(11); // test
2290  CheckLocationNameMultiMap(12); // test
2291  }
2292  Utilities->CallLogPop(432);
2293  return;
2294  }
2295  else
2296  {
2297  Utilities->CallLogPop(433);
2298  return;
2299  }
2300  }
2301 // check if a level crossing - OK if placed on a plain straight track
2302  if(TempTrackElement.TrackType == LevelCrossing)
2303  {
2304  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1049, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2305  {
2306  TrackPush(11, TempTrackElement);
2307  PlotRaisedLinkedLevelCrossingBarriers(0, TrackElementAt(1050, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2308 // no need for reference to LC element as can't be open
2309  TrackLinkingRequiredFlag = true;
2310  Utilities->CallLogPop(1907);
2311  return;
2312  }
2313  else
2314  {
2315  Utilities->CallLogPop(1906);
2316  return; // was a level crossing but can't place it for some reason
2317  }
2318  }
2319 
2320 // check if another element already there
2321  else if(FoundFlag || InactiveFoundFlag)
2322  {
2323  Utilities->CallLogPop(434);
2324  return; // something already there (active or inactive track)
2325  }
2326 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2327 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2328 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2329 // do this after pushed into vector so that can use EnterLocationName
2330 
2331  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2332  {
2333  TrackPush(3, TempTrackElement);
2334  SearchForAndUpdateLocationName(3, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2335  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2336  }
2337  else if(TempTrackElement.TrackType == Points)
2338  {
2339  TrackPush(4, TempTrackElement);
2340  bool BothPointFillets = true;
2341  PlotPoints(6, TempTrackElement, Display, BothPointFillets);
2342  }
2343  else if(TempTrackElement.TrackType == SignalPost)
2344  {
2345  TrackPush(10, TempTrackElement);
2346  PlotSignal(12, TempTrackElement, Display);
2347  }
2348  else
2349  {
2350  TrackPush(5, TempTrackElement);
2351  TempTrackElement.PlotVariableTrackElement(1, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2352  }
2353  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2354  {
2355  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2356  }
2357  if(InternalChecks)
2358  {
2359  CheckMapAndTrack(2); // test
2360  CheckMapAndInactiveTrack(2); // test
2361  CheckLocationNameMultiMap(5); // test
2362  }
2363  Utilities->CallLogPop(2062);
2364 }
2365 
2366 // ---------------------------------------------------------------------------
2367 
2368 void TTrack::PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag,
2369  bool InternalChecks)
2370 // new at v2.2.0 - similar to above but keeping speed & length attributes (for pasting) and also pastes location names
2371 {
2372  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPastedTrackElementWithAttributes," + AnsiString(HLocInput) + "," +
2373  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2374  bool PlatAllowedFlag = false;
2375 
2376  TrackLinkingRequiredFlag = false;
2377  TLocationNameMultiMapEntry LocationNameEntry;
2378 
2379  LocationNameEntry.first = "";
2380  if(TempTrackElement.SpeedTag == 0)
2381  {
2382  Utilities->CallLogPop(2063);
2383  return; // not assigned yet
2384  }
2385  TempTrackElement.HLoc = HLocInput;
2386  TempTrackElement.VLoc = VLocInput;
2387  for(int x = 0; x < 4; x++) // unset any gaps
2388  {
2389  if(TempTrackElement.Config[x] == Gap)
2390  {
2391  TempTrackElement.ConnLinkPos[x] = -1;
2392  }
2393  TempTrackElement.Conn[x] = -1;
2394  }
2395  SetElementID(5, TempTrackElement); // TempTrackElement is the one to be added
2396 // new at version 0.6 - set signal aspect depending on build mode
2397  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2398  int VecPos = GetVectorPositionFromTrackMap(56, HLocInput, VLocInput, FoundFlag); // active track already there
2399 
2400  // if find an active track element (as has been pasted into track vector when dealing with inactive elements in SelectVector)
2401  // )set its ActiveTrackElementName to same name as the inactive element (from SelectVector). Note that can't use LocationName
2402  // for the active track element because these aren't set
2403  // if don't do this then get a mismatch error during map checks later
2404 
2405  // if(FoundFlag) TrackElementAt(xx, VecPos).ActiveTrackElementName = TempTrackElement.LocationName; //doesn't work!!
2406 
2407  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(26, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2408  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2409 
2410  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2411  {
2412  if(InactiveTrackElementAt(119, IMPair.first).TrackType == NamedNonStationLocation)
2413  {
2414  NonStationOrLevelCrossingPresent = true;
2415  }
2416  if(InactiveTrackElementAt(120, IMPair.first).TrackType == LevelCrossing)
2417  {
2418  NonStationOrLevelCrossingPresent = true;
2419  }
2420  if(InactiveTrackElementAt(121, IMPair.first).TrackType == Platform)
2421  {
2422  PlatformPresent = true;
2423  }
2424  // no need to check IMPair.second since if that exists it is because .first is a platform
2425  InactiveSpeedTag1 = InactiveTrackElementAt(122, IMPair.first).SpeedTag;
2426  InactiveSpeedTag2 = InactiveTrackElementAt(123, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2427  }
2428 // check platforms
2429  if(TempTrackElement.TrackType == Platform)
2430  {
2431  if(FoundFlag) // active track element already there
2432  {
2433  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2434  {
2435  ;
2436  }
2437  // same platform type already there so above keeps PlatAllowedFlag false
2438  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1051, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2439  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2440  {
2441  PlatAllowedFlag = true;
2442  }
2443  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1052, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2444  {
2445  PlatAllowedFlag = true;
2446  }
2447  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1053, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2448  {
2449  PlatAllowedFlag = true;
2450  }
2451  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1054, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2452  {
2453  PlatAllowedFlag = true;
2454  }
2455  if(PlatAllowedFlag)
2456  {
2457  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2458  TrackPush(12, TempTrackElement);
2459 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2460  {
2461  SearchForAndUpdateLocationName(4, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2462  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2463  }
2464  // Must be called AFTER TrackPush
2465 // No need to plot the element - Clearand ... called after this function called
2466  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2467  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2468 // drop in v2.4.0 if(TrackElementAt(907, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2469 // AnsiString(TrackElementAt(908, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2470 // TrackElementAt(909, VecPos).Length01 = DefaultTrackLength;
2471  if(InternalChecks)
2472  {
2473  CheckMapAndInactiveTrack(12); // test
2474  CheckLocationNameMultiMap(20); // test
2475  }
2476  Utilities->CallLogPop(2064);
2477  return;
2478  }
2479  } // if(FoundFlag)
2480 
2481  Utilities->CallLogPop(2065);
2482  return;
2483  } // if platform
2484 
2485 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2486  if(TempTrackElement.TrackType == NamedNonStationLocation)
2487  {
2488  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1055, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2489  (!FoundFlag && !InactiveFoundFlag))
2490  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2491  {
2492  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2493  TrackPush(13, TempTrackElement);
2494 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2495  {
2496  SearchForAndUpdateLocationName(5, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2497  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2498  }
2499  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2500  {
2501 // drop in v2.4.0 if(TrackElementAt(910, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2502 // AnsiString(TrackElementAt(911, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2503 // TrackElementAt(912, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2504  }
2505  if(InternalChecks)
2506  {
2507  CheckMapAndInactiveTrack(13); // test
2508  CheckLocationNameMultiMap(21); // test
2509  }
2510  Utilities->CallLogPop(2066);
2511  return;
2512  }
2513  else
2514  {
2515  Utilities->CallLogPop(2067);
2516  return;
2517  }
2518  }
2519 // check if a level crossing - OK if placed on a plain straight track
2520  if(TempTrackElement.TrackType == LevelCrossing)
2521  {
2522  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1056, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2523  {
2524  TrackPush(14, TempTrackElement);
2525  PlotRaisedLinkedLevelCrossingBarriers(3, TrackElementAt(1057, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2526 // no need for reference to LC element as can't be open
2527  TrackLinkingRequiredFlag = true;
2528  Utilities->CallLogPop(2068);
2529  return;
2530  }
2531  else
2532  {
2533  Utilities->CallLogPop(2069);
2534  return; // was a level crossing but can't place it for some reason
2535  }
2536  }
2537 
2538 // check if another element already there
2539  else if(FoundFlag || InactiveFoundFlag)
2540  {
2541  Utilities->CallLogPop(2070);
2542  return; // something already there (active or inactive track)
2543  }
2544 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2545 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2546 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2547 // do this after pushed into vector so that can use EnterLocationName
2548 
2549  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2550  {
2551  TrackPush(15, TempTrackElement);
2552  SearchForAndUpdateLocationName(6, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2553  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2554  }
2555  else if(TempTrackElement.TrackType == Points)
2556  {
2557  TrackPush(16, TempTrackElement);
2558  bool BothPointFillets = true;
2559  PlotPoints(7, TempTrackElement, Display, BothPointFillets);
2560  }
2561  else if(TempTrackElement.TrackType == SignalPost)
2562  {
2563  TrackPush(17, TempTrackElement);
2564  PlotSignal(14, TempTrackElement, Display);
2565  }
2566  else
2567  {
2568  TrackPush(18, TempTrackElement);
2569  TempTrackElement.PlotVariableTrackElement(6, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2570  }
2571  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2572  {
2573  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2574  }
2575  if(InternalChecks)
2576  {
2577  CheckMapAndTrack(12); // test
2578  CheckMapAndInactiveTrack(14); // test
2579  CheckLocationNameMultiMap(22); // test
2580  }
2581  Utilities->CallLogPop(2071);
2582 }
2583 
2584 // ---------------------------------------------------------------------------
2585 
2586 bool TTrack::TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
2587 // GiveMessages relates to the call to LinkTrack or LinkTrackNoMessages
2588 // return bool = true for success
2589 // LocError = true for location error & HLoc & VLoc to be inverted
2590 {
2591  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TryToConnectTrack," + AnsiString((short)GiveMessages));
2592  LocError = false;
2593  SetTrackFinished(false);
2594  if(TrackVector.size() == 0)
2595  {
2596  Utilities->CallLogPop(437);
2597  return(false);
2598  }
2599  if(GapsUnset(7))
2600  {
2601  if(GiveMessages)
2602  {
2603  ShowMessage("Gaps must be set before track can be validated");
2604  }
2605  Utilities->CallLogPop(1135);
2606  return(false);
2607  }
2608 // below sets all Conns and CLks to -1 except for gapjumps that match and are properly set,
2609 // returns true for any unset gaps
2611  {
2612  // can keep this exception as protected by the GapsUnset call above
2613  throw Exception("Error, gaps unset when TryToConnectTrack called");
2614  }
2616  CheckGapMap(1); // test
2617 // Gap connections now securely defined
2618 
2619  CheckMapAndTrack(8); // test
2620 
2621 // Perform a pre-check prior to TrackMap being compiled
2622  if(GiveMessages)
2623  {
2624  if(!LinkTrack(1, LocError, HLoc, VLoc, false))
2625  {
2626  Utilities->CallLogPop(439);
2627  return(false);
2628  }
2629  }
2630  else
2631  {
2632  if(!LinkTrackNoMessages(1, false))
2633  {
2634  Utilities->CallLogPop(1131);
2635  return(false);
2636  }
2637  }
2638 // here if pre-check successful
2639  if(!RepositionAndMapTrack(0))
2640  {
2641  ShowMessage("Error in RepositionAndMapTrack during TryToConnectTrack. Railway file is corrupt, further use may cause a system crash");
2642  Utilities->CallLogPop(1138);
2643  return(false);
2644  }
2645 // now perform the final assembly - FinalCall = true
2646  if(GiveMessages)
2647  {
2648  if(!LinkTrack(2, LocError, HLoc, VLoc, true))
2649  {
2650  Utilities->CallLogPop(1116);
2651  return(false);
2652  }
2653  }
2654  else
2655  {
2656  if(!LinkTrackNoMessages(2, true))
2657  {
2658  Utilities->CallLogPop(1132);
2659  return(false);
2660  }
2661  }
2662 // success
2663 
2664  PopulateLCVector(0);
2665  CheckGapMap(2); // test
2666  CheckMapAndTrack(3); // test
2667  CheckMapAndInactiveTrack(3); // test
2668  CheckLocationNameMultiMap(9); // test
2669  SetTrackFinished(true);
2670 
2671 // Build ContinuationNameMap
2672  std::pair<AnsiString, char>TempMapPair;
2673 
2674  ContinuationNameMap.clear();
2675  for(int x = 0; x < Track->TrackVectorSize(); x++)
2676  {
2677  if((Track->TrackElementAt(1058, x).TrackType == Continuation) && (Track->TrackElementAt(1059, x).ActiveTrackElementName != ""))
2678  {
2679  TempMapPair.first = Track->TrackElementAt(1060, x).ActiveTrackElementName;
2680  TempMapPair.second = 'x'; // unused
2681  ContinuationNameMap.insert(TempMapPair);
2682  }
2683  }
2684 
2685 //check (provided TrackFinished is true) if any named (red) locations are without platforms, ie concourses only or concourses and foot crossings
2686 //(don't report blue areas without track as these unlikely to be mistakes)
2687 
2688  if(TrackFinished)
2689  {
2690  AnsiString Name = "";
2691  typedef std::list<AnsiString> TNoPlatsList;
2692  TNoPlatsList::iterator NPLIt;
2693  TNoPlatsList NoPlatsList;
2694  typedef std::list<AnsiString> TLocNameList;
2695  TLocNameList LocNameList; //single entry for each name
2698  for(TLocationNameMultiMapIterator LNMMIt = LocationNameMultiMap.begin(); LNMMIt != LocationNameMultiMap.end(); LNMMIt++)
2699  {
2700  LocNameList.push_back(LNMMIt->first);
2701  }
2702  LocNameList.sort();
2703  LocNameList.unique();
2704  for(TLocNameList::iterator LNLIt = LocNameList.begin(); LNLIt != LocNameList.end(); LNLIt++)
2705  {
2706  Name = *LNLIt;
2707  MMRange = LocationNameMultiMap.equal_range(Name);
2708  if(MMRange.first == MMRange.second) //can't find it - should always do but include as a safeguard
2709  {
2710  continue;
2711  }
2712  for(TLocationNameMultiMapIterator LNMMIt = MMRange.first; LNMMIt != MMRange.second; LNMMIt++)
2713  {
2714  if((LNMMIt->second) < 0) //active track element
2715  {
2716  if(TrackElementAt(1401, -1 - LNMMIt->second).TrackType != FootCrossing)
2717  {
2718  break;
2719  }
2720  }
2721  else //inactive
2722  {
2723  if(InactiveTrackElementAt(1402, LNMMIt->second).TrackType != Concourse)
2724  {
2725  break;
2726  }
2727  }
2728  TempIt = MMRange.second;
2729  if(LNMMIt == --TempIt) //reached last named element & all concourses or foot crossings
2730  {
2731  NoPlatsList.push_back(Name);
2732  }
2733  }
2734  }
2735  if(!NoPlatsList.empty())
2736  {
2737  AnsiString NoPlatsAnsiList = "";
2738  for(NPLIt = NoPlatsList.begin(); NPLIt != NoPlatsList.end(); NPLIt++)
2739  {
2740  NoPlatsAnsiList += *NPLIt + '\n';
2741  }
2742  if(!NoPlatsMessageSent)
2743  {
2744  if(NoPlatsList.size() > 1)
2745  {
2746  ShowMessage("Please note: the following locations have no platforms, trains won't be able to stop or pass there:-\n\n" + NoPlatsAnsiList + "\nThis message will not be shown again.");
2747  }
2748  else
2749  {
2750  ShowMessage("Please note: the following location has no platforms, trains won't be able to stop or pass there:-\n\n" + NoPlatsAnsiList + "\nThis message will not be shown again.");
2751  }
2752  NoPlatsMessageSent = true;
2753  }
2754  }
2755  }
2756  Utilities->CallLogPop(440);
2757  return(true);
2758 }
2759 
2760 // ---------------------------------------------------------------------------
2761 bool TTrack::ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
2762 // unused - too time-consuming - double brute force search
2763 {
2764  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErrorInTrackBeforeSetGaps");
2765  int NewHLoc, NewVLoc;
2766  bool ConnectionFoundFlag, LinkFoundFlag;
2767 
2768  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
2769  {
2770  for(unsigned int y = 0; y < 4; y++) // check all links for each element
2771  {
2772  if(TrackElementAt(1061, x).Link[y] <= 0)
2773  {
2774  continue; // no link
2775  }
2776  if(TrackElementAt(1062, x).Config[y] == End)
2777  {
2778  continue; // buffer or continuation
2779  }
2780  if(TrackElementAt(1063, x).Config[y] == Gap)
2781  {
2782  continue; // gap jump
2783  }
2784  // get required H & V for track element joining link 'y'
2785  NewHLoc = TrackElementAt(1064, x).HLoc + LinkHVArray[TrackElementAt(1065, x).Link[y]][0];
2786  NewVLoc = TrackElementAt(1066, x).VLoc + LinkHVArray[TrackElementAt(1067, x).Link[y]][1];
2787  // find track element if present
2788  ConnectionFoundFlag = false;
2789  for(unsigned int z = 0; z < TrackVector.size(); z++)
2790  {
2791 // if(TrackElementAt(5, z).TrackType == Platform)
2792 // continue; //skip platforms
2793  if((TrackElementAt(1068, z).HLoc == NewHLoc) && (TrackElementAt(1069, z).VLoc == NewVLoc))
2794  {
2795  ConnectionFoundFlag = true;
2796  // find connecting link in the newly found track element if there is one
2797  LinkFoundFlag = false;
2798  for(unsigned int a = 0; a < 4; a++)
2799  {
2800  if(TrackElementAt(1070, z).Link[a] == (10 - TrackElementAt(1071, x).Link[y]))
2801  {
2802  LinkFoundFlag = true;
2803  }
2804  }
2805  // if there isn't a corresponding link set the invert values for the offending element
2806  if(!LinkFoundFlag)
2807  {
2808  HLoc = TrackElementAt(1072, x).HLoc;
2809  VLoc = TrackElementAt(1073, x).VLoc;
2810  Utilities->CallLogPop(441);
2811  return(true);
2812  }
2813  break; // success, so break out of 'z' loop
2814  } // if((TrackElementAt(, z).HLoc== NewHLoc) &&....
2815 
2816  } // for z...
2817  // if there isn't a connection set the invert values for the offending element
2818  if(!ConnectionFoundFlag)
2819  {
2820  HLoc = TrackElementAt(1074, x).HLoc;
2821  VLoc = TrackElementAt(1075, x).VLoc;
2822  Utilities->CallLogPop(442);
2823  return(true);
2824  }
2825  } // for y....
2826  } // for x...
2827  Utilities->CallLogPop(443);
2828  return(false); // all OK
2829 }
2830 
2831 // ---------------------------------------------------------------------------
2832 
2833 bool TTrack::FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement) // true if find one
2834 {
2835  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNonPlatformMatch," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
2836  TrackElement.LogTrack(0));
2837  bool FoundFlag;
2838 
2839  Position = GetVectorPositionFromTrackMap(13, HLoc, VLoc, FoundFlag);
2840  if(FoundFlag)
2841  {
2842  TrackElement = TrackElementAt(1076, Position);
2843  }
2844  Utilities->CallLogPop(444);
2845  return(FoundFlag);
2846 }
2847 
2848 // ---------------------------------------------------------------------------
2849 
2851 {
2852  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextTrackElement");
2853  if(NextTrackElementPtr >= TrackVector.end())
2854  {
2855  Utilities->CallLogPop(1336);
2856  return(false);
2857  }
2858  Next = *NextTrackElementPtr;
2860  Utilities->CallLogPop(1337);
2861  return(true);
2862 }
2863 
2864 // ---------------------------------------------------------------------------
2865 
2867 {
2868  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextInactiveTrackElement");
2870  {
2871  Utilities->CallLogPop(1338);
2872  return(false);
2873  }
2874  Next = *NextTrackElementPtr;
2876  Utilities->CallLogPop(1339);
2877  return(true);
2878 }
2879 
2880 // ---------------------------------------------------------------------------
2881 
2882 int TTrack::NumberOfGaps(int Caller)
2883 
2884 {
2885  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfGaps");
2886  int Count = 0;
2887 
2888  if(TrackVector.size() == 0)
2889  {
2890  Utilities->CallLogPop(1340);
2891  return(0);
2892  }
2893  for(unsigned int x = 0; x < TrackVector.size(); x++)
2894  {
2895  if(TrackElementAt(1077, x).TrackType == GapJump)
2896  {
2897  Count++;
2898  }
2899  }
2900  Utilities->CallLogPop(1341);
2901  return(Count);
2902 }
2903 
2904 // ---------------------------------------------------------------------------
2906 // above sets all Conns and CLks to -1 except for gapjumps that match and are properly set
2907 // returns true for any unset gaps
2908 {
2909  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetConnClkCheckUnsetGapJumps");
2910  bool UnsetGaps = false;
2911 
2912  if(TrackVector.size() == 0)
2913  {
2914  Utilities->CallLogPop(445);
2915  return(false);
2916  }
2917  for(unsigned int x = 0; x < TrackVector.size(); x++)
2918  {
2919  if(TrackElementAt(1078, x).TrackType != GapJump)
2920  {
2921  for(unsigned int y = 0; y < 4; y++)
2922  {
2923  TrackElementAt(1079, x).Conn[y] = -1;
2924  TrackElementAt(1080, x).ConnLinkPos[y] = -1;
2925  }
2926  }
2927  else // GapJump
2928  {
2929 // int tempint = TrackElementAt(, x).Conn[0);
2930 
2931  if(TrackElementAt(1081, x).Conn[0] == -1) // unset if -1
2932  {
2933  for(unsigned int y = 0; y < 4; y++)
2934  {
2935  TrackElementAt(1082, x).Conn[y] = -1;
2936  TrackElementAt(1083, x).ConnLinkPos[y] = -1;
2937  }
2938  UnsetGaps = true;
2939  continue; // to next 'x'
2940  }
2941  else // set, but may not have matching element, or that element may not be set
2942  {
2943  for(unsigned int y = 1; y < 4; y++) // reset the non-gap values anyway, gap always at position 0
2944  {
2945  TrackElementAt(1084, x).Conn[y] = -1;
2946  TrackElementAt(1085, x).ConnLinkPos[y] = -1;
2947  }
2948 
2949  if(TrackElementAt(1086, TrackElementAt(1104, x).Conn[0]).TrackType != GapJump)
2950  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks & reset Lk[0]
2951  {
2952  for(unsigned int y = 0; y < 4; y++)
2953  {
2954  TrackElementAt(1087, x).Conn[y] = -1;
2955  TrackElementAt(1088, x).ConnLinkPos[y] = -1;
2956  }
2957  UnsetGaps = true;
2958  continue; // to next 'x'
2959  }
2960 // here if gap connection is itself a GapJump
2961  if(TrackElementAt(1089, TrackElementAt(1105, x).Conn[0]).Conn[0] != (int)x)
2962  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
2963  // if not clear Conns & CLks & reset Lk[0]
2964  {
2965  for(unsigned int y = 0; y < 4; y++)
2966  {
2967  TrackElementAt(1090, x).Conn[y] = -1;
2968  TrackElementAt(1091, x).ConnLinkPos[y] = -1;
2969  }
2970  UnsetGaps = true;
2971  continue; // to next 'x'
2972  }
2973 // here if gap connection itself points back to 'x' so these two GapJumps match properly
2974 // hence no more action needed on these Conns & CLks
2975  }
2976  } // else //gap jump
2977 
2978  } // for x...
2979  Utilities->CallLogPop(446);
2980  return(UnsetGaps);
2981 }
2982 
2983 // ---------------------------------------------------------------------------
2984 
2985 void TTrack::LoadTrack(int Caller, std::ifstream& VecFile, bool &GraphicsFollow)
2986 {
2987 // VecFile already open and its pointer at right place on calling
2988  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTrack");
2989  int TempInt;
2990 
2991  TrackClear(1);
2992 // load track elements
2993  int NumberOfActiveElements = 0;
2994 
2995  GraphicsFollow = false;
2996  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
2997  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // **Active elements** marker, if last character is '1' then there are graphics to be loaded
2998 
2999  if(MarkerString[MarkerString.Length()] == '1')
3000  {
3001  GraphicsFollow = true;
3002  }
3003  for(int x = 0; x < NumberOfActiveElements; x++)
3004  {
3005  VecFile >> TempInt; // TrackVectorNumber, not used
3006  VecFile >> TempInt; // SpeedTag
3007  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
3008  VecFile >> TempInt;
3009  TrackElement.HLoc = TempInt;
3010  VecFile >> TempInt;
3011  TrackElement.VLoc = TempInt;
3012  if(TrackElement.TrackType == GapJump)
3013  {
3014  VecFile >> TempInt;
3015  TrackElement.ConnLinkPos[0] = TempInt;
3016  VecFile >> TempInt;
3017  TrackElement.Conn[0] = TempInt;
3018  }
3019  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3020  {
3021  VecFile >> TempInt;
3022  TrackElement.Attribute = TempInt;
3023  }
3024  if(TrackElement.TrackType == SignalPost)
3025  {
3026  VecFile >> TempInt;
3027  if(TempInt == 0)
3028  {
3029  TrackElement.CallingOnSet = false;
3030  }
3031  else
3032  {
3033  TrackElement.CallingOnSet = true;
3034  }
3035  }
3036  VecFile >> TempInt;
3037  TrackElement.Length01 = TempInt;
3038  VecFile >> TempInt;
3039  TrackElement.Length23 = TempInt;
3040  VecFile >> TempInt;
3041  if((TempInt != -1) && (TempInt < 10))
3042  {
3043  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
3044  }
3045  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
3046  {
3047  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
3048  }
3049  TrackElement.SpeedLimit01 = TempInt;
3050  VecFile >> TempInt;
3051  if((TempInt != -1) && (TempInt < 10))
3052  {
3053  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
3054  }
3055  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
3056  {
3057  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
3058  }
3059  TrackElement.SpeedLimit23 = TempInt;
3060 
3061  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3062  TrackElement.ActiveTrackElementName = Utilities->LoadFileString(VecFile);
3063  SetElementID(0, TrackElement);
3064  AnsiString Marker = Utilities->LoadFileString(VecFile); // marker
3065 // new for v0.6
3066  if(TrackElement.TrackType == SignalPost)
3067  {
3068  if(Marker[1] == '3')
3069  {
3070  TrackElement.SigAspect = TTrackElement::ThreeAspect;
3071  }
3072  else if(Marker[1] == '2')
3073  {
3074  TrackElement.SigAspect = TTrackElement::TwoAspect;
3075  }
3076  else if(Marker[1] == 'G')
3077  {
3078  TrackElement.SigAspect = TTrackElement::GroundSignal;
3079  }
3080  else
3081  {
3082  TrackElement.SigAspect = TTrackElement::FourAspect;
3083  }
3084  }
3085  if(TrackElement.SpeedTag != 0)
3086  {
3087  TrackPush(8, TrackElement); // don't save default elements (now dispensed with)
3088  }
3089  }
3090  int NumberOfInactiveElements = 0;
3091 
3092  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3093  Utilities->LoadFileString(VecFile); // **Inactive elements** marker
3094  for(int x = 0; x < NumberOfInactiveElements; x++)
3095  {
3096  VecFile >> TempInt; // InactiveTrackVectorNumber - not used, only used for identification in file
3097  VecFile >> TempInt; // SpeedTag
3098  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
3099  VecFile >> TempInt;
3100  TrackElement.HLoc = TempInt;
3101  VecFile >> TempInt;
3102  TrackElement.VLoc = TempInt;
3103  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3104  SetElementID(3, TrackElement);
3105  TrackPush(9, TrackElement);
3106  Utilities->LoadFileString(VecFile); // marker
3107  }
3108  bool LocError = false; // needed for TryToConnectTrack but not used
3109  int H = -1, V = -1; // needed for TryToConnectTrack but not used
3110 
3111  if(TryToConnectTrack(2, LocError, H, V, false)) // false for don't give messages
3112  {
3113  SetTrackFinished(true);
3114  }
3115  else
3116  {
3117  SetTrackFinished(false);
3118  }
3119 // CheckMapAndTrack(9); all these checked in TryToConnectTrack
3120 // CheckMapAndInactiveTrack(8);
3121 // CheckLocationNameMultiMap(10);
3122  Utilities->CallLogPop(448);
3123 }
3124 
3125 // ---------------------------------------------------------------------------
3126 
3127 void TTrack::LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3128 {
3129 // VecFile already open and its pointer at right place on calling
3130  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGraphics, " + GraphicsPath);
3131 // first int is number of graphics, then each graphic, create in UserGraphicMap, derive Width & height from TPicture
3132 // & load into UserGraphicItem then store in UserGraphicVector
3133  UserGraphicVector.clear();
3134  TUserGraphicItem UGI;
3135  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3136 
3137  for(int x = 0; x < NumberOfGraphics; x++)
3138  {
3139  UGI.FileName = GraphicsPath + "\\" + Utilities->LoadFileString(VecFile);
3140  UGI.HPos = Utilities->LoadFileInt(VecFile);
3141  UGI.VPos = Utilities->LoadFileInt(VecFile);
3142  UGI.Width = 0; // provisional value
3143  UGI.Height = 0; // provisional value
3144  UGI.UserGraphic = NULL; // provisional value
3145  UserGraphicVector.push_back(UGI);
3146  }
3147 // now load the map & set Width, Height & TPicture*
3148  bool FileError = false;
3149 
3150  for(int x = 0; x < NumberOfGraphics; x++)
3151  {
3152  if(FileError)
3153  {
3154  break; // otherwise keeps going round the loop
3155  }
3156  UGI = UserGraphicVectorAt(0, x);
3157  if(UserGraphicMap.empty()) // will be when x == 0 but not after
3158  {
3159  try
3160  {
3161 // TUserGraphicMapEntry UGME; //can't define it here, it has to be defined before it is used - now defined in TrackUnit.h
3162  UGME.first = UGI.FileName;
3163  UGME.second = new TPicture;
3164  UGME.second->LoadFromFile(UGME.first); // errors caught below
3165  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3166  {
3167  throw Exception("Map Insertion Error 2 - UserGraphicMap insertion failure for " + UGI.FileName);
3168  }
3169  UGI.UserGraphic = UGME.second;
3170  UGI.Width = UGI.UserGraphic->Width;
3171  UGI.Height = UGI.UserGraphic->Height;
3172  UserGraphicVectorAt(1, x) = UGI;
3173  }
3174  catch(const EInvalidGraphic &e) //non error catch - CallLogPop called at end of function
3175  {
3176  //message already sent in CheckUserGraphics
3177  FileError = true;
3178  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3179  if(!UserGraphicMap.empty())
3180  {
3181  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3182  {
3183  delete UGMIt->second;
3184  }
3185  UserGraphicMap.clear();
3186  }
3187  }
3188  catch(const Exception &e) //non error catch - CallLogPop called at end of function
3189  {
3190  //message already sent in CheckUserGraphics
3191  FileError = true;
3192  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3193  if(!UserGraphicMap.empty())
3194  {
3195  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3196  {
3197  delete UGMIt->second;
3198  }
3199  UserGraphicMap.clear();
3200  }
3201  }
3202  }
3203  else
3204  {
3205  bool FoundInMap = false;
3206  for(TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3207  {
3208  if(UGI.FileName == UGMIt->first) // already exists in map
3209  {
3210  UGI.UserGraphic = UGMIt->second;
3211  UGI.Width = UGI.UserGraphic->Width;
3212  UGI.Height = UGI.UserGraphic->Height;
3213  UserGraphicVectorAt(2, x) = UGI;
3214  FoundInMap = true;
3215  break;
3216  }
3217  }
3218  if(!FoundInMap)
3219  {
3220  try
3221  {
3223  UGME.first = UGI.FileName;
3224  UGME.second = new TPicture;
3225  UGME.second->LoadFromFile(UGME.first); // errors caught below
3226  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3227  {
3228  throw Exception("Map Insertion Error 3 - UserGraphicMap insertion failure for " + UGI.FileName);
3229  }
3230  UGI.UserGraphic = UGME.second;
3231  UGI.Width = UGI.UserGraphic->Width;
3232  UGI.Height = UGI.UserGraphic->Height;
3233  UserGraphicVectorAt(3, x) = UGI;
3234  }
3235  catch(const EInvalidGraphic &e) //non error catch - CallLogPop called at end of function
3236  {
3237  //message already sent in CheckUserGraphics
3238  FileError = true;
3239  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3240  if(!UserGraphicMap.empty())
3241  {
3242  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3243  {
3244  delete UGMIt->second;
3245  }
3246  UserGraphicMap.clear();
3247  }
3248  }
3249  catch(const Exception &e) //non error catch - CallLogPop called at end of function
3250  {
3251  //message already sent in CheckUserGraphics
3252  FileError = true;
3253  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3254  if(!UserGraphicMap.empty())
3255  {
3256  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3257  {
3258  delete UGMIt->second;
3259  }
3260  UserGraphicMap.clear();
3261  }
3262  }
3263  }
3264  }
3265  }
3266  Utilities->CallLogPop(2167);
3267 }
3268 
3269 // ---------------------------------------------------------------------------
3270 
3271 void TTrack::SaveTrack(int Caller, std::ofstream& VecFile, bool GraphicsFollow)
3272 {
3273 // VecFile already open and its pointer at right place on calling
3274 // if GraphicsFollow true, then save Marker as **Active elements**1
3275 // save trackfinished flag
3276  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTrack, " + AnsiString(int(GraphicsFollow)));
3277  TTrackElement TrackElement, InactiveTrackElement;
3278 
3279 // save track elements
3280  Utilities->SaveFileInt(VecFile, TrackVector.size());
3281  if(GraphicsFollow)
3282  {
3283  VecFile << "**Active elements**1" << '\0' << '\n';
3284  }
3285  else
3286  {
3287  VecFile << "**Active elements**" << '\0' << '\n';
3288  }
3289  for(unsigned int x = 0; x < (TrackVector.size()); x++)
3290  {
3291  TrackElement = TrackElementAt(1092, x);
3292  VecFile << x << '\n'; // this is the TrackVectorNumber - extra, so easier to identify in the file
3293  VecFile << TrackElement.SpeedTag << '\n';
3294  VecFile << TrackElement.HLoc << '\n';
3295  VecFile << TrackElement.VLoc << '\n';
3296  if(TrackElement.TrackType == GapJump)
3297  {
3298  VecFile << TrackElement.ConnLinkPos[0] << '\n';
3299  VecFile << TrackElement.Conn[0] << '\n';
3300  }
3301  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3302  {
3303  VecFile << TrackElement.Attribute << '\n';
3304  }
3305  if(TrackElement.TrackType == SignalPost)
3306  {
3307  if(TrackElement.CallingOnSet)
3308  {
3309  VecFile << int(1) << '\n';
3310  }
3311  else
3312  {
3313  VecFile << int(0) << '\n';
3314  }
3315  }
3316  VecFile << TrackElement.Length01 << '\n';
3317  VecFile << TrackElement.Length23 << '\n';
3318  VecFile << TrackElement.SpeedLimit01 << '\n';
3319  VecFile << TrackElement.SpeedLimit23 << '\n';
3320  VecFile << TrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3321  VecFile << TrackElement.ActiveTrackElementName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3322 // new for v0.6
3323  if(TrackElement.TrackType == SignalPost)
3324  {
3325  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
3326  {
3327  VecFile << "3*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3328  }
3329  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
3330  {
3331  VecFile << "2*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3332  }
3333  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
3334  {
3335  VecFile << "G*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3336  }
3337  else // 4 aspect
3338  {
3339  VecFile << "4*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3340  }
3341  }
3342  else
3343  {
3344  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3345  }
3346  }
3347 
3348  Utilities->SaveFileInt(VecFile, InactiveTrackVector.size());
3349  VecFile << "**Inactive elements**" << '\0' << '\n'; // extra
3350  for(unsigned int x = 0; x < (InactiveTrackVector.size()); x++)
3351  {
3352  InactiveTrackElement = InactiveTrackElementAt(136, x);
3353  VecFile << x << '\n'; // this is the Inactive TrackVectorNumber - extra
3354  VecFile << InactiveTrackElement.SpeedTag << '\n';
3355  VecFile << InactiveTrackElement.HLoc << '\n';
3356  VecFile << InactiveTrackElement.VLoc << '\n';
3357  VecFile << InactiveTrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3358  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3359  }
3360  Utilities->CallLogPop(449);
3361 }
3362 
3363 // ---------------------------------------------------------------------------
3364 
3365 bool TTrack::CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream& VecFile)
3366 {
3367 // VecFile already open and its pointer at right place on calling
3368 // check trackfinished flag
3369 // inactive elements follow immediately after active elements, no need to check for a marker between them
3370  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTrackElementsInFile");
3371  int TempInt;
3372 
3373  GraphicsFollow = false;
3374  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
3375  if((NumberOfActiveElements < 0) || (NumberOfActiveElements > 1000000)) // No of active elements (up to 500 screens all completely full!)
3376  {
3377  Utilities->CallLogPop(1513);
3378  return(false);
3379  }
3380 // if(!Utilities->CheckAndCompareFileString(VecFile, "**Active elements**")) dropped at v2.4.0 as could have a '1' at the end if there are graphics
3381  AnsiString MarkerString;
3382 
3383  if(!Utilities->CheckAndReadFileString(VecFile, MarkerString)) // new version for v2.4.0
3384  {
3385  Utilities->CallLogPop(1758);
3386  return(false);
3387  }
3388  if(MarkerString[MarkerString.Length()] == '1')
3389  {
3390  GraphicsFollow = true;
3391  }
3392  for(int x = 0; x < NumberOfActiveElements; x++)
3393  {
3394  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3395  {
3396  Utilities->CallLogPop(1759);
3397  return(false);
3398  }
3399  VecFile >> TempInt;
3400  int SpeedTag = TempInt;
3401  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3402  {
3403  Utilities->CallLogPop(1514);
3404  return(false);
3405  }
3406  VecFile >> TempInt;
3407  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3408  {
3409  Utilities->CallLogPop(1495);
3410  return(false);
3411  }
3412  VecFile >> TempInt;
3413  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3414  {
3415  Utilities->CallLogPop(1497);
3416  return(false);
3417  }
3418  if((SpeedTag > 87) && (SpeedTag < 96)) // GapJumps 88-95 incl
3419  {
3420  VecFile >> TempInt;
3421  if((TempInt < -1) || (TempInt > 3)) // ConnLinkPos[0]
3422  {
3423  Utilities->CallLogPop(1499);
3424  return(false);
3425  }
3426  VecFile >> TempInt;
3427  if((TempInt < -1) || (TempInt > 999999)) // Conn[0]
3428  {
3429  Utilities->CallLogPop(1500);
3430  return(false);
3431  }
3432  }
3433  if(((SpeedTag >= 7) && (SpeedTag <= 14)) || ((SpeedTag >= 28) && (SpeedTag <= 43)) || ((SpeedTag >= 132) && (SpeedTag <= 139)) ||
3434  ((SpeedTag >= 68) && (SpeedTag <= 75)))
3435  {
3436  VecFile >> TempInt;
3437  if((TempInt < -1) || (TempInt > 5)) // Points & signal attribute
3438  {
3439  Utilities->CallLogPop(1502);
3440  return(false);
3441  }
3442  }
3443  if((SpeedTag >= 68) && (SpeedTag <= 75)) // signals
3444  {
3445  VecFile >> TempInt;
3446  if((TempInt != 0) && (TempInt != 1)) // CallingOnSet
3447  {
3448  Utilities->CallLogPop(1155);
3449  return(false);
3450  }
3451  }
3452  VecFile >> TempInt;
3453  if((TempInt < -1) || (TempInt > 999999)) // Length01
3454  {
3455  Utilities->CallLogPop(1503);
3456  return(false);
3457  }
3458  VecFile >> TempInt;
3459  if((TempInt < -1) || (TempInt > 999999)) // Length23
3460  {
3461  Utilities->CallLogPop(1504);
3462  return(false);
3463  }
3464  VecFile >> TempInt;
3465  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit01
3466  {
3467  Utilities->CallLogPop(1505);
3468  return(false);
3469  }
3470  VecFile >> TempInt;
3471  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit23
3472  {
3473  Utilities->CallLogPop(1506);
3474  return(false);
3475  }
3476  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3477  {
3478  Utilities->CallLogPop(1142);
3479  return(false); // LocationName
3480  }
3481  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3482  {
3483  Utilities->CallLogPop(1143);
3484  return(false); // ActiveTrackElementName
3485  }
3486  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3487  {
3488  Utilities->CallLogPop(1787);
3489  return(false); // marker
3490  }
3491  }
3492  int NumberOfInactiveElements = 0;
3493 
3494  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3495  if(NumberOfInactiveElements < 0) // No of active elements
3496  {
3497  Utilities->CallLogPop(1493);
3498  return(false);
3499  }
3500  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3501  {
3502  Utilities->CallLogPop(1764);
3503  return(false); // **Inactive elements** marker
3504  }
3505  for(int x = 0; x < NumberOfInactiveElements; x++)
3506  {
3507  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3508  {
3509  Utilities->CallLogPop(1765);
3510  return(false);
3511  }
3512  VecFile >> TempInt;
3513  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3514  {
3515  Utilities->CallLogPop(1494);
3516  return(false);
3517  }
3518  VecFile >> TempInt;
3519  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3520  {
3521  Utilities->CallLogPop(1496);
3522  return(false);
3523  }
3524  VecFile >> TempInt;
3525  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3526  {
3527  Utilities->CallLogPop(1498);
3528  return(false);
3529  }
3530  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3531  {
3532  Utilities->CallLogPop(1144);
3533  return(false); // LocationName
3534  }
3535  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3536  {
3537  Utilities->CallLogPop(1788);
3538  return(false); // marker
3539  }
3540  }
3541  Utilities->CallLogPop(1507);
3542  return(true);
3543 }
3544 
3545 // ---------------------------------------------------------------------------
3546 
3547 bool TTrack::CheckUserGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3548 {
3549  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckUserGraphics");
3550  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3551 
3552  if((NumberOfGraphics < 0) || (NumberOfGraphics > 100000)) // 100,000 should be plenty!
3553  {
3554  Utilities->CallLogPop(2168);
3555  return(false);
3556  }
3557  // filename in Graphics folder, then HPos, then VPos
3558  AnsiString FileName = "", TempStr = "";
3559 
3560  for(int x = 0; x < NumberOfGraphics; x++)
3561  {
3562  TPicture *TempPicture = new TPicture;
3563  try
3564  {
3565  if(!Utilities->CheckAndReadFileString(VecFile, FileName))
3566  {
3567  Utilities->CallLogPop(2169);
3568  delete TempPicture;
3569  return(false);
3570  }
3571  TempPicture->LoadFromFile(GraphicsPath + "\\" + FileName); // only loaded to check and catch errors
3572  delete TempPicture;
3573  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // HPos, allow plenty of scope
3574  {
3575  Utilities->CallLogPop(2170);
3576  return(false);
3577  }
3578  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // VPos
3579  {
3580  Utilities->CallLogPop(2171);
3581  return(false);
3582  }
3583  }
3584  catch(const EInvalidGraphic &e) //non error catch
3585  {
3586  //move file pointer to end of graphic section for later checks in session files
3587  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3588  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3589  for(int y = x + 1; y < NumberOfGraphics; y++)
3590  {
3591  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3592  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3593  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3594  }
3595  ShowMessage(FileName +
3596  " has an incorrect file format, user graphics can't be loaded. Ensure that all user graphic files are valid with extension .bmp, .gif, .jpg, or .png");
3597  Utilities->CallLogPop(2172);
3598  delete TempPicture;
3599  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3600  }
3601  catch(const Exception &e) //non error catch
3602  {
3603  //move file pointer to end of graphic section for later checks in session files
3604  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3605  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3606  for(int y = x + 1; y < NumberOfGraphics; y++)
3607  {
3608  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3609  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3610  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3611  }
3612  ShowMessage("Unable to load user graphic files, ensure that " + FileName +
3613  " exists in the 'Graphics' folder and that it is has extension .bmp, .gif, .jpg, or .png.");
3614  Utilities->CallLogPop(2173);
3615  delete TempPicture;
3616  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3617  }
3618  }
3619  Utilities->CallLogPop(2174);
3620  return(true);
3621 }
3622 
3623 // ---------------------------------------------------------------------------
3624 
3625 void TTrack::SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
3626 {
3627  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSessionBarriersDownVector");
3628  int VecSize = Track->BarriersDownVector.size();
3629 
3630  Utilities->SaveFileInt(OutFile, VecSize);
3631  for(int x = 0; x < VecSize; x++)
3632  {
3634  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3635  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3636  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3637  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3638  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3639  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3640  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3641  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3642  }
3643  Utilities->CallLogPop(1963);
3644 }
3645 
3646 // ---------------------------------------------------------------------------
3647 
3648 void TTrack::SaveChangingLCVector(int Caller, std::ofstream &OutFile) //used only in errorfile
3649 {
3650  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveChangingLCVector");
3651  int VecSize = Track->ChangingLCVector.size();
3652 
3653  Utilities->SaveFileInt(OutFile, VecSize);
3654  for(int x = 0; x < VecSize; x++)
3655  {
3657  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3658  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3659  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3660  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3661  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3662  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3663  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3664  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3665  }
3666  Utilities->CallLogPop(1980);
3667 }
3668 
3669 // ---------------------------------------------------------------------------
3670 
3671 bool TTrack::CheckActiveLCVector(int Caller, std::ifstream &VecFile)
3672 {
3673  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckActiveLCVector");
3674  int VecSize = Utilities->LoadFileInt(VecFile);
3675 
3676  for(int x = 0; x < VecSize; x++)
3677  {
3678  if(!Utilities->CheckFileInt(VecFile, 0, 2)) //changed from bool at v2.6.0 to allow TypeOfRoute == 2 for barriers manually lowered
3679  {
3680  Utilities->CallLogPop(1970);
3681  return(false);
3682  }
3683  if(!Utilities->CheckFileBool(VecFile))
3684  {
3685  Utilities->CallLogPop(1971);
3686  return(false);
3687  }
3688  if(!Utilities->CheckFileInt(VecFile, 0, 3))
3689  {
3690  Utilities->CallLogPop(1972);
3691  return(false);
3692  }
3693  if(!Utilities->CheckFileDouble(VecFile))
3694  {
3695  Utilities->CallLogPop(1973);
3696  return(false);
3697  }
3698  if(!Utilities->CheckFileInt(VecFile, 1, 2))
3699  {
3700  Utilities->CallLogPop(1974);
3701  return(false);
3702  }
3703  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3704  {
3705  Utilities->CallLogPop(1975);
3706  return(false);
3707  }
3708  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3709  {
3710  Utilities->CallLogPop(1976);
3711  return(false);
3712  }
3713  if(!Utilities->CheckFileDouble(VecFile))
3714  {
3715  Utilities->CallLogPop(1977);
3716  return(false);
3717  }
3718  }
3719  Utilities->CallLogPop(1978);
3720  return(true);
3721 }
3722 
3723 // ---------------------------------------------------------------------------
3724 
3725 void TTrack::LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
3726 {
3727  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadBarriersDownVector");
3728  int VecSize = Utilities->LoadFileInt(VecFile);
3729 
3730  for(int x = 0; x < VecSize; x++)
3731  {
3732  TActiveLevelCrossing TALC;
3733  TALC.TypeOfRoute = Utilities->LoadFileInt(VecFile); //changed to int from bool in v2.6.0
3734  TALC.ReducedTimePenalty = Utilities->LoadFileBool(VecFile);
3735  TALC.BarrierState = TBarrierState(Utilities->LoadFileInt(VecFile));
3736  TALC.ChangeDuration = Utilities->LoadFileDouble(VecFile);
3737  TALC.BaseElementSpeedTag = Utilities->LoadFileInt(VecFile);
3738  TALC.HLoc = Utilities->LoadFileInt(VecFile);
3739  TALC.VLoc = Utilities->LoadFileInt(VecFile);
3740  TALC.StartTime = TDateTime(Utilities->LoadFileDouble(VecFile));
3741  BarriersDownVector.push_back(TALC);
3742  }
3743  Utilities->CallLogPop(1979);
3744 }
3745 
3746 // ---------------------------------------------------------------------------
3747 
3748 void TTrack::RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
3749 /*
3750  Note, have to plot inactives before track because track has to overwrite NamedNonStationLocations, but, plot basic LC's (if flag set) after track
3751  so they lie above the track. Basic LCs are plotted for all but Level1Mode == OperMode (i.e. closed to trains), because the LC attributes will always be
3752  0 in such cases and because in OperMode the LCs have to be plotted again after the routes, which is done in Clearand....
3753 */
3754 {
3755  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildTrackAndText," + AnsiString((short)BothPointFilletsAndBasicLCs));
3756  TTrackElement Next;
3757 
3758 // Disp->ClearDisplay();
3760  while(ReturnNextInactiveTrackElement(0, Next))
3761  {
3762  if(Next.TrackType != LevelCrossing) // don't plot level crossings as these need to be plotted after the track
3763  {
3764  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3765  {
3766  // only plot if on screen, to save time
3767  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3769  {
3770  Next.PlotVariableTrackElement(2, Disp); // striped if not named
3771  }
3772  }
3773  }
3774  }
3775 
3776  TextHandler->RebuildFromTextVector(1, Disp); // plot text after inactives so can have text on stations etc
3777 
3778  NextTrackElementPtr = TrackVector.begin();
3779  while(ReturnNextTrackElement(0, Next))
3780  {
3781  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3782  {
3783  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3785  {
3786  if(Next.TrackType == Points)
3787  {
3788  PlotPoints(5, Next, Disp, BothPointFilletsAndBasicLCs);
3789  }
3790  else if(Next.TrackType == SignalPost)
3791  {
3792  PlotSignal(9, Next, Disp);
3793  }
3794  else if(Next.TrackType == GapJump)
3795  {
3796  PlotGap(0, Next, Disp);
3797  }
3798  else if(Next.TrackType == Continuation) //added for multiplayer graphic overlays
3799  {
3800  PlotContinuation(0, Next, Disp);
3801  }
3802  else
3803  {
3804  Next.PlotVariableTrackElement(3, Disp); // for footcrossings, may be striped or not
3805  }
3806  }
3807  }
3808  }
3809 
3810  if(BothPointFilletsAndBasicLCs)
3811  {
3813  while(ReturnNextInactiveTrackElement(4, Next))
3814  {
3815  if(Next.TrackType == LevelCrossing) // plot level crossings (if required) after the track
3816  {
3817  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3818  {
3819  // only plot if on screen, to save time, & OK as plotting one by one here
3820  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3822  {
3823  if(GetTrackElementFromTrackMap(1, Next.HLoc, Next.VLoc).SpeedTag == 1)
3824  {
3825  Disp->PlotOutput(193, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothVer);
3826  }
3827  else
3828  {
3829  Disp->PlotOutput(194, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothHor);
3830  }
3831  }
3832  }
3833  }
3834  }
3835  }
3836  Disp->Update();
3837  Utilities->CallLogPop(468);
3838 }
3839 
3840 // ---------------------------------------------------------------------------
3841 
3842 void TTrack::RebuildUserGraphics(int Caller, TDisplay *Disp) // new at v2.4.0
3843 {
3844  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildUserGraphics,");
3845  if(UserGraphicVector.empty())
3846  {
3847  Utilities->CallLogPop(2175);
3848  return;
3849  }
3850  TUserGraphicItem UGI;
3851 
3852  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
3853  {
3854  UGI = UserGraphicVectorAt(4, x);
3855  if(((UGI.HPos + UGI.Width - (Display->DisplayOffsetH * 16)) >= 0) && ((UGI.HPos - (Display->DisplayOffsetH * 16)) <
3856  (Utilities->ScreenElementWidth * 16)) && ((UGI.VPos + UGI.Height - (Display->DisplayOffsetV * 16)) >= 0) &&
3857  ((UGI.VPos - (Display->DisplayOffsetV * 16)) < (Utilities->ScreenElementHeight * 16)))
3858  {
3859  Disp->PlotAndAddUserGraphic(0, UGI);
3860  }
3861  }
3862  Disp->Update();
3863  Utilities->CallLogPop(2176);
3864 }
3865 
3866 // ---------------------------------------------------------------------------
3867 
3868 void TTrack::WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap) //added text after inactives at v2.10.0
3869 /*
3870  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
3871 */
3872 {
3873  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteTrackAndTextToImage");
3874 // need to change graphics back to black on white if have a dark background
3875  TColor OldTransparentColour = Utilities->clTransparent;
3876 
3878  {
3879  Utilities->clTransparent = TColor(0xFFFFFF); // white
3882  }
3883  TTrackElement Next;
3884 
3885  Bitmap->Canvas->CopyMode = cmSrcCopy;
3887  Graphics::TBitmap *GraphicOutput;
3888 
3889  while(ReturnNextInactiveTrackElement(2, Next))
3890  {
3891  GraphicOutput = Next.GraphicPtr;
3892  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3893  {
3894  if(Next.LocationName == "") // plot as named or unnamed (striped)
3895  {
3896  // default is not striped
3897  switch(Next.SpeedTag)
3898  {
3899  case 76: // t platform
3900  GraphicOutput = RailGraphics->gl76Striped;
3901  break;
3902 
3903  case 77: // h platform
3904  GraphicOutput = RailGraphics->bm77Striped;
3905  break;
3906 
3907  case 78: // v platform
3908  GraphicOutput = RailGraphics->bm78Striped;
3909  break;
3910 
3911  case 79: // r platform
3912  GraphicOutput = RailGraphics->gl79Striped;
3913  break;
3914 
3915  case 96: // concourse
3916  GraphicOutput = RailGraphics->ConcourseStriped;
3917  break;
3918 
3919  case 129: // v footbridge
3920  GraphicOutput = RailGraphics->gl129Striped;
3921  break;
3922 
3923  case 130: // h footbridge
3924  GraphicOutput = RailGraphics->gl130Striped;
3925  break;
3926 
3927  case 131: // non-station named loc
3928  GraphicOutput = RailGraphics->bmNameStriped;
3929  break;
3930 
3931  case 145: // v underpass
3932  GraphicOutput = RailGraphics->gl145Striped;
3933  break;
3934 
3935  case 146: // h underpass
3936  GraphicOutput = RailGraphics->gl146Striped;
3937  break;
3938 
3939  default:
3940  GraphicOutput = Next.GraphicPtr;
3941  break;
3942  }
3943  }
3944  if(Next.SpeedTag == 144) // level crossing
3945  {
3946  if(GetTrackElementFromTrackMap(2, Next.HLoc, Next.VLoc).SpeedTag == 1)
3947  {
3948  GraphicOutput = RailGraphics->LCBothVer;
3949  }
3950  else
3951  {
3952  GraphicOutput = RailGraphics->LCBothHor;
3953  }
3954  }
3955  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
3956  }
3957  }
3958 
3959  TextHandler->WriteTextToImage(0, Bitmap); //so overwrites inactive elements //added at v2.10.0
3960 
3961 
3962  NextTrackElementPtr = TrackVector.begin();
3963  while(ReturnNextTrackElement(2, Next))
3964  {
3965  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3966  {
3967  if(Next.TrackType == Points) // plot both fillets
3968  {
3969  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
3970  if(Next.SpeedTag < 28)
3971  {
3972  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3974  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3976  }
3977  else if(Next.SpeedTag < 132)
3978  {
3979  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3980  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][0]);
3981  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3982  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][1]);
3983  }
3984  else
3985  {
3986  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3987  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][0]);
3988  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3989  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][1]);
3990  }
3991  }
3992  else if(Next.TrackType == GapJump) // plot as connected or unconnected
3993  {
3994  if((Next.SpeedTag == 88) && (Next.Conn[0] > -1))
3995  {
3996  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
3997  }
3998  else if((Next.SpeedTag == 88) && (Next.Conn[0] == -1))
3999  {
4000  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88unset);
4001  }
4002  if((Next.SpeedTag == 89) && (Next.Conn[0] > -1))
4003  {
4004  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
4005  }
4006  else if((Next.SpeedTag == 89) && (Next.Conn[0] == -1))
4007  {
4008  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89unset);
4009  }
4010  if((Next.SpeedTag == 90) && (Next.Conn[0] > -1))
4011  {
4012  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4013  }
4014  else if((Next.SpeedTag == 90) && (Next.Conn[0] == -1))
4015  {
4016  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90unset);
4017  }
4018  if((Next.SpeedTag == 91) && (Next.Conn[0] > -1))
4019  {
4020  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4021  }
4022  else if((Next.SpeedTag == 91) && (Next.Conn[0] == -1))
4023  {
4024  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91unset);
4025  }
4026  if((Next.SpeedTag == 92) && (Next.Conn[0] > -1))
4027  {
4028  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4029  }
4030  else if((Next.SpeedTag == 92) && (Next.Conn[0] == -1))
4031  {
4032  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92unset);
4033  }
4034  if((Next.SpeedTag == 93) && (Next.Conn[0] > -1))
4035  {
4036  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4037  }
4038  else if((Next.SpeedTag == 93) && (Next.Conn[0] == -1))
4039  {
4040  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93unset);
4041  }
4042  if((Next.SpeedTag == 94) && (Next.Conn[0] > -1))
4043  {
4044  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4045  }
4046  else if((Next.SpeedTag == 94) && (Next.Conn[0] == -1))
4047  {
4048  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94unset);
4049  }
4050  if((Next.SpeedTag == 95) && (Next.Conn[0] > -1))
4051  {
4052  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4053  }
4054  else if((Next.SpeedTag == 95) && (Next.Conn[0] == -1))
4055  {
4056  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95unset);
4057  }
4058  }
4059  // below added for version 0.6, only stop signals to be drawn
4060  else if(Next.TrackType == SignalPost)
4061  {
4062  for(int x = 0; x < 40; x++)
4063  {
4064  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 0)) // need to plot as red regardless of actual attribute value
4065  {
4066  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4067  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4068  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4069  int HOffset = 0;
4070  if(Next.SpeedTag > 73)
4071  {
4072  HOffset = 5;
4073  }
4074  else if(Next.SpeedTag == 71)
4075  {
4076  HOffset = 9;
4077  }
4078  int VOffset = 0;
4079  if(Next.SpeedTag == 69)
4080  {
4081  VOffset = 9;
4082  }
4083  else if(Next.SpeedTag == 72)
4084  {
4085  VOffset = 5;
4086  }
4087  else if(Next.SpeedTag == 74)
4088  {
4089  VOffset = 5;
4090  }
4091  Graphics::TBitmap *GraphicPtr;
4092  if(Next.SpeedTag > 71)
4093  {
4094  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4095  }
4096  else if(Next.SpeedTag < 70)
4097  {
4098  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4099  }
4100  else
4101  {
4102  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4103  }
4104  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4105  // plot special signal platform if present
4106  Graphics::TBitmap* SignalPlatformGraphic;
4107  if(PlatformOnSignalSide(2, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic)) //
4108  {
4109  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4110  }
4111  // now plot signal (double yellow overwrites most of signal platform if present)
4112  // below amended for version 0.6
4114  {
4115  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4116  }
4117  else if(Next.SigAspect == TTrackElement::TwoAspect)
4118  {
4119  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4120  }
4121  else if(Next.SigAspect == TTrackElement::GroundSignal)
4122  {
4123  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4124  }
4125  else // 4 aspect
4126  {
4127  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4128  }
4129  break;
4130  }
4131  }
4132  }
4133  else
4134  {
4135  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4136  }
4137  }
4138  }
4139  if(OldTransparentColour != clB5G5R5)
4140  {
4141  Utilities->clTransparent = OldTransparentColour; // restore
4144  }
4145  Utilities->CallLogPop(1533);
4146 }
4147 
4148 // ---------------------------------------------------------------------------
4149 
4150 void TTrack::WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
4151 {
4152  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteGraphicsToImage");
4153  if(UserGraphicVector.empty())
4154  {
4155  Utilities->CallLogPop(2192);
4156  return;
4157  }
4158  else
4159  {
4160  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
4161  {
4162  Bitmap->Canvas->CopyMode = cmSrcCopy;
4163  Bitmap->Canvas->Draw(UserGraphicVectorAt(26, x).HPos - (GetHLocMin() * 16), UserGraphicVectorAt(27, x).VPos - (GetVLocMin() * 16),
4164  UserGraphicVectorAt(28, x).UserGraphic->Graphic);
4165  }
4166  }
4167  Utilities->CallLogPop(2193);
4168 }
4169 
4170 // ---------------------------------------------------------------------------
4171 
4172 void TTrack::WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
4173 /*
4174  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
4175  Here plot all named elements as non-striped, points with active fillet, signals as they are set, and gaps as connected
4176 */
4177 {
4178  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteOperatingTrackAndTextToImage");
4179 // need to change graphics back to black on white if have a dark background
4180  TColor OldTransparentColour = Utilities->clTransparent;
4181 
4183  {
4184  Utilities->clTransparent = TColor(0xFFFFFF); // white
4187  }
4188  TTrackElement Next;
4189 
4190  Bitmap->Canvas->CopyMode = cmSrcCopy;
4192  Graphics::TBitmap *GraphicOutput;
4193 
4194  while(ReturnNextInactiveTrackElement(3, Next))
4195  {
4196  GraphicOutput = Next.GraphicPtr; // no striped name graphics
4197  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4198  {
4199  if(Next.SpeedTag == 144) // level crossing
4200  {
4201  int BaseElement = GetTrackElementFromTrackMap(3, Next.HLoc, Next.VLoc).SpeedTag;
4202  if(BaseElement == 1) // hor element
4203  {
4204  if(Next.Attribute == 1) // open to trains
4205  {
4206  GraphicOutput = RailGraphics->LCBothHor;
4207  }
4208  else // plot as closed to trains if in any other state
4209  {
4210  GraphicOutput = RailGraphics->LCBothVer;
4211  }
4212  }
4213  else // vert element
4214  {
4215  if(Next.Attribute == 1) // open to trains
4216  {
4217  GraphicOutput = RailGraphics->LCBothVer;
4218  }
4219  else // plot as closed to trains if in any other state
4220  {
4221  GraphicOutput = RailGraphics->LCBothHor;
4222  }
4223  }
4224  }
4225  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
4226  }
4227  }
4228 
4229  TextHandler->WriteTextToImage(1, Bitmap); //added at v2.10.0
4230 
4231  NextTrackElementPtr = TrackVector.begin();
4232  while(ReturnNextTrackElement(3, Next))
4233  {
4234  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4235  {
4236  if(Next.TrackType == Points) // plot active fillet
4237  {
4238  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4239  if(Next.SpeedTag < 28)
4240  {
4241  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4243  }
4244  else if(Next.SpeedTag < 132)
4245  {
4246  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4248  }
4249  else
4250  {
4251  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4253  }
4254  if(Next.Failed) //added at v2.13.0
4255  {
4256  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4258  }
4259 
4260  }
4261  else if(Next.TrackType == GapJump) // plot as connected
4262  {
4263  if(Next.SpeedTag == 88)
4264  {
4265  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
4266  }
4267  else if(Next.SpeedTag == 89)
4268  {
4269  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
4270  }
4271  else if(Next.SpeedTag == 90)
4272  {
4273  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4274  }
4275  else if(Next.SpeedTag == 91)
4276  {
4277  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4278  }
4279  else if(Next.SpeedTag == 92)
4280  {
4281  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4282  }
4283  else if(Next.SpeedTag == 93)
4284  {
4285  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4286  }
4287  else if(Next.SpeedTag == 94)
4288  {
4289  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4290  }
4291  else if(Next.SpeedTag == 95)
4292  {
4293  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4294  }
4295  }
4296  else if(Next.TrackType == SignalPost) // plot in correct colour
4297  {
4298  for(int x = 0; x < 40; x++)
4299  {
4300  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == Next.Attribute))
4301  {
4302  // plot blank first, then plot platform if present - (always not striped for operating railway)
4303  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4304  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4305  int HOffset = 0;
4306  if(Next.SpeedTag > 73)
4307  {
4308  HOffset = 5;
4309  }
4310  else if(Next.SpeedTag == 71)
4311  {
4312  HOffset = 9;
4313  }
4314  int VOffset = 0;
4315  if(Next.SpeedTag == 69)
4316  {
4317  VOffset = 9;
4318  }
4319  else if(Next.SpeedTag == 72)
4320  {
4321  VOffset = 5;
4322  }
4323  else if(Next.SpeedTag == 74)
4324  {
4325  VOffset = 5;
4326  }
4327  Graphics::TBitmap *GraphicPtr;
4328  if(Next.SpeedTag > 71)
4329  {
4330  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4331  }
4332  else if(Next.SpeedTag < 70)
4333  {
4334  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4335  }
4336  else
4337  {
4338  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4339  }
4340  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4341  // plot special signal platform if present
4342  Graphics::TBitmap* SignalPlatformGraphic;
4343  if(PlatformOnSignalSide(1, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4344  {
4345  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4346  }
4347  if(!Next.Failed)
4348  {
4349  // now plot signal (double yellow overwrites most of signal platform if present)
4350  // below amended for version 0.6
4352  {
4353  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4354  }
4355  else if(Next.SigAspect == TTrackElement::TwoAspect)
4356  {
4357  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4358  }
4359  else if(Next.SigAspect == TTrackElement::GroundSignal)
4360  {
4361  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4362  }
4363  else // 4 aspect
4364  {
4365  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4366  }
4367  if((Next.CallingOnSet) && (Next.SigAspect != TTrackElement::GroundSignal))
4368  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
4369  {
4370  if(Next.SpeedTag == 68)
4371  {
4372  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm68CallingOn);
4373  }
4374  if(Next.SpeedTag == 69)
4375  {
4376  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm69CallingOn);
4377  }
4378  if(Next.SpeedTag == 70)
4379  {
4380  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm70CallingOn);
4381  }
4382  if(Next.SpeedTag == 71)
4383  {
4384  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm71CallingOn);
4385  }
4386  if(Next.SpeedTag == 72)
4387  {
4388  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm72CallingOn);
4389  }
4390  if(Next.SpeedTag == 73)
4391  {
4392  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm73CallingOn);
4393  }
4394  if(Next.SpeedTag == 74)
4395  {
4396  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm74CallingOn);
4397  }
4398  if(Next.SpeedTag == 75)
4399  {
4400  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm75CallingOn);
4401  }
4402  }
4403  else if((Next.CallingOnSet) && (Next.SigAspect == TTrackElement::GroundSignal)) // ground signal calling on, use normal proceed aspect
4404  {
4405  for(int x = 0; x < 40; x++)
4406  {
4407  if((SigTableGroundSignal[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
4408  {
4409  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4410  Display->PlotSignalBlankOnBitmap(Next.HLoc - GetHLocMin(), Next.VLoc - GetVLocMin(), Next.SpeedTag, Bitmap,
4411  Utilities->RHSignalFlag); // in case existing signal is a double yellow
4412  // plot special signal platform if present
4413  Graphics::TBitmap* SignalPlatformGraphic;
4414  if(PlatformOnSignalSide(4, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4415  {
4416  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4417  }
4418  // now plot signal
4419  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4420  break;
4421  }
4422  }
4423  }
4424  break;
4425  }
4426  else //added at v2.13.0
4427  {
4428  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, FailedSigTable[x % 5].SigPtr);
4429  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->BlackOctagon);
4430  break;
4431  }
4432  }
4433  }
4434  }
4435  else
4436  {
4437  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4438  if(Next.Failed) //added at v2.13.0
4439  {
4440  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4442  }
4443  }
4444  }
4445  }
4446  if(OldTransparentColour != clB5G5R5)
4447  {
4448  Utilities->clTransparent = OldTransparentColour; // restore
4451  }
4452  Utilities->CallLogPop(1701);
4453 }
4454 
4455 // ---------------------------------------------------------------------------
4456 
4457 bool TTrack::FindAndHighlightAnUnsetGap(int Caller) // true if find one
4458 {
4459  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindAndHighlightAnUnsetGap");
4460  for(unsigned int x = 0; x < TrackVector.size(); x++)
4461  {
4462  if(TrackElementAt(1093, x).TrackType == GapJump)
4463  {
4464  if(TrackElementAt(1094, x).Conn[0] > -1)
4465  {
4466  continue; // to next 'x' value as this element has already been set
4467  }
4468  // here if identify a GapJump element not yet set
4469  GapPos = x;
4470  GapHLoc = TrackElementAt(1095, x).HLoc;
4471  GapVLoc = TrackElementAt(1096, x).VLoc;
4472  // highlight it
4474  Utilities->CallLogPop(469);
4475  return(true);
4476  }
4477  }
4478  Utilities->CallLogPop(470);
4479  return(false);
4480 }
4481 
4482 // ---------------------------------------------------------------------------
4483 
4484 bool TTrack::FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc) // true if find one
4485 {
4486  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindSetAndDisplayMatchingGap," + AnsiString(HLoc) + "," +
4487  AnsiString(VLoc));
4488  int Position;
4489  TTrackElement TrackElement;
4490 
4491  if(!(FindNonPlatformMatch(11, HLoc, VLoc, Position, TrackElement)))
4492  {
4493  Utilities->CallLogPop(471);
4494  return(false); // not found
4495  }
4496  if(TrackElement.TrackType != GapJump)
4497  {
4498  Utilities->CallLogPop(472);
4499  return(false); // found something but not a gap
4500  }
4501  if(Position == GapPos)
4502  {
4503  Utilities->CallLogPop(473);
4504  return(false); // selected original gap
4505  }
4506  if(TrackElementAt(1097, Position).Conn[0] != -1)
4507  {
4508  Utilities->CallLogPop(474);
4509  return(false); // already selected
4510  }
4511  TrackElementAt(1098, Position).Conn[0] = GapPos; // set Conn[0] at Position to GapPos & ConnLinkPos[0] to 0
4512  TrackElementAt(1099, Position).ConnLinkPos[0] = 0;
4513  TrackElementAt(1100, GapPos).Conn[0] = Position; // set other one similarly
4514  TrackElementAt(1101, GapPos).ConnLinkPos[0] = 0;
4515 // now highlight the selected location
4516  Display->Ellipse(0, HLoc * 16, VLoc * 16, clB0G5R0);
4517  Utilities->CallLogPop(475);
4518  return(true);
4519 }
4520 
4521 // ---------------------------------------------------------------------------
4522 
4523 bool TTrack::GapsUnset(int Caller)
4524 // returns true if there are gaps and any are unset
4525 {
4526  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GapsUnset");
4527  if(TrackVector.size() == 0)
4528  {
4529  Utilities->CallLogPop(476);
4530  return(false);
4531  }
4532  for(unsigned int x = 0; x < TrackVector.size(); x++)
4533  {
4534  if(TrackElementAt(1102, x).TrackType == GapJump)
4535  {
4536  if(TrackElementAt(1103, x).Conn[0] == -1) // unset if -1 (Gap always at position 0)
4537  {
4538  Utilities->CallLogPop(477);
4539  return(true);
4540  }
4541  else // set, but may not have matching element, or that element may not be set
4542  {
4543  if(TrackElementAt(1106, TrackElementAt(1107, x).Conn[0]).TrackType != GapJump)
4544  // check that the element pointed to by the gap link is a GapJump
4545  {
4546  ShowMessage("Error - gap connected to a non-gap. Railway file is corrupt, further use may cause a system crash");
4547  Utilities->CallLogPop(1137);
4548  return(false);
4549  }
4550 // here if gap connection is itself a GapJump
4551  if(TrackElementAt(1108, TrackElementAt(1109, x).Conn[0]).Conn[0] != (int)x)
4552  // check that the element pointed to by the gap link is a GapJump & that its gap link
4553  // points back to 'x'
4554  {
4555  Utilities->CallLogPop(478);
4556  return(true);
4557  }
4558 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4559  }
4560  } // if(TrackElementAt(, x).TrackType == GapJump)
4561 
4562  } // for x...
4563  Utilities->CallLogPop(479);
4564  return(false);
4565 }
4566 
4567 // ---------------------------------------------------------------------------
4568 
4569 bool TTrack::NoGaps(int Caller) // returns true if there are no gaps
4570 {
4571  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoGaps");
4572  for(unsigned int x = 0; x < TrackVector.size(); x++)
4573  {
4574  if(TrackElementAt(1110, x).TrackType == GapJump)
4575  {
4576  Utilities->CallLogPop(1105);
4577  return(false);
4578  }
4579  }
4580  Utilities->CallLogPop(1106);
4581  return(true);
4582 }
4583 
4584 // ---------------------------------------------------------------------------
4585 
4586 bool TTrack::NoNamedLocationElements(int Caller) // returns true if there are no NamedLocationElements (includes footcrossings)
4587 {
4588  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoLocations");
4589  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4590  {
4591  if(InactiveTrackElementAt(137, x).FixedNamedLocationElement)
4592  {
4593  Utilities->CallLogPop(1107);
4594  return(false);
4595  }
4596  }
4597  for(unsigned int x = 0; x < TrackVector.size(); x++)
4598  {
4599  if(TrackElementAt(1111, x).FixedNamedLocationElement)
4600  {
4601  Utilities->CallLogPop(1108);
4602  return(false);
4603  }
4604  }
4605  Utilities->CallLogPop(1109);
4606  return(true);
4607 }
4608 
4609 // ---------------------------------------------------------------------------
4610 
4612 // returns true if there are unnamed NamedLocationElements (includes footcrossings)
4613 // returns false otherwise or if there are no NamedLocationElements
4614 {
4615  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationsNotNamed");
4616  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4617  {
4618  if(InactiveTrackElementAt(138, x).FixedNamedLocationElement)
4619  {
4620  if(InactiveTrackElementAt(139, x).LocationName == "")
4621  {
4622  Utilities->CallLogPop(1110);
4623  return(true);
4624  }
4625  }
4626  }
4627  for(unsigned int x = 0; x < TrackVector.size(); x++)
4628  {
4629  if(TrackElementAt(1112, x).FixedNamedLocationElement)
4630  {
4631  if(TrackElementAt(1113, x).LocationName == "")
4632  {
4633  Utilities->CallLogPop(1111);
4634  return(true);
4635  }
4636  }
4637  }
4638  Utilities->CallLogPop(1112);
4639  return(false);
4640 }
4641 
4642 // ---------------------------------------------------------------------------
4643 
4644 void TTrack::ShowSelectedGap(int Caller, TDisplay *Disp)
4645 {
4646  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ShowSelectedGap,");
4647  Disp->Ellipse(1, GapHLoc * 16, GapVLoc * 16, clB0G0R5);
4648  Utilities->CallLogPop(480);
4649 }
4650 
4651 // ---------------------------------------------------------------------------
4652 
4654 {
4655  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAnyNonMatchingGaps");
4656  if(TrackVector.size() == 0)
4657  {
4658  Utilities->CallLogPop(481);
4659  return;
4660  }
4661  for(unsigned int x = 0; x < TrackVector.size(); x++)
4662  {
4663  if(TrackElementAt(1114, x).TrackType == GapJump)
4664  {
4665  if(TrackElementAt(1115, x).Conn[0] > -1) // set
4666  {
4667  if(TrackElementAt(1116, TrackElementAt(1117, x).Conn[0]).TrackType != GapJump)
4668  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks
4669  {
4670  TrackElementAt(1118, x).Conn[0] = -1;
4671  TrackElementAt(1119, x).ConnLinkPos[0] = -1;
4672  continue; // to next 'x'
4673  }
4674 // here if gap connection is itself a GapJump
4675  if(TrackElementAt(1120, TrackElementAt(1349, x).Conn[0]).Conn[0] != (int)x)
4676  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
4677  // if not clear Conns & CLks
4678  {
4679  TrackElementAt(1121, x).Conn[0] = -1;
4680  TrackElementAt(1122, x).ConnLinkPos[0] = -1;
4681  continue; // to next 'x'
4682  }
4683 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4684 // hence no more action needed on these Conns & CLks
4685  }
4686  } // else //gap jump
4687 
4688  } // for x...
4689 // throw Exception("Test Exception");//test
4690  Utilities->CallLogPop(482);
4691 }
4692 
4693 // ---------------------------------------------------------------------------
4694 
4695 void TTrack::ResetSignals(int Caller)
4696 {
4697  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetSignals");
4698  for(unsigned int x = 0; x < TrackVector.size(); x++)
4699  {
4700  if(TrackElementAt(1123, x).TrackType == SignalPost)
4701  {
4702  TrackElementAt(1124, x).Attribute = 0;
4703  TrackElementAt(1514, x).Failed = false;
4704  FailedSignalsVector.clear();
4705  }
4706  }
4707  Utilities->CallLogPop(483);
4708 }
4709 
4710 // ---------------------------------------------------------------------------
4711 
4712 void TTrack::ResetPoints(int Caller)
4713 {
4714  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetPoints");
4715  for(unsigned int x = 0; x < TrackVector.size(); x++)
4716  {
4717  if(TrackElementAt(1125, x).TrackType == Points)
4718  {
4719  TrackElementAt(1126, x).Attribute = 0;
4720  TrackElementAt(1515, x).Failed = false;
4721  FailedPointsVector.clear();
4722  }
4723  }
4724  Utilities->CallLogPop(484);
4725 }
4726 
4727 // ---------------------------------------------------------------------------
4728 
4729 bool TTrack::RepositionAndMapTrack(int Caller) // doesn't involve InactiveTrack
4730 {
4731  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RepositionAndMapTrack");
4732  if(TrackVector.empty())
4733  {
4734  TrackMap.clear();
4735  Utilities->CallLogPop(485);
4736  return(true);
4737  }
4738 // build new vector from map (map already in ascending order of locations & no erase elements in map)
4739  THVPair TrackMapKeyPair;
4740 
4741  NewVector.clear();
4742  TTrackMapIterator TrackMapPtr;
4743 
4744  if(!TrackMap.empty())
4745  {
4746  for(TrackMapPtr = TrackMap.begin(); TrackMapPtr != TrackMap.end(); TrackMapPtr++)
4747  {
4748  NewVector.push_back(TrackElementAt(6, TrackMapPtr->second));
4749  }
4750  }
4751  if(NewVector.size() != TrackMap.size())
4752  {
4753  throw Exception("Error - Map & Vector different sizes");
4754  }
4755  unsigned int NonZeroCount = 0;
4756 
4757  for(unsigned int x = 0; x < TrackVector.size(); x++)
4758  {
4759  if(TrackElementAt(1127, x).TrackType != Erase)
4760  {
4761  NonZeroCount++;
4762  }
4763  }
4764  if(NewVector.size() != NonZeroCount)
4765  {
4766  throw Exception("Error - NewVector & NonZero TrackVector different sizes");
4767  }
4769  TrackMap.clear(); // ready to rebuild map after repositioning of TrackVector elements
4770  TTrackMapEntry TrackMapEntry;
4771 
4772  for(unsigned int x = 0; x < TrackVector.size(); x++)
4773  {
4774  TrackMapKeyPair.first = TrackElementAt(1128, x).HLoc;
4775  TrackMapKeyPair.second = TrackElementAt(1129, x).VLoc;
4776  TrackMapEntry.first = TrackMapKeyPair;
4777  TrackMapEntry.second = x;
4778  if(!(TrackMap.insert(TrackMapEntry).second))
4779  {
4780  throw Exception("Error - map insertion failure, TrackVector in error");
4781  }
4782  }
4783 // All track now relocated in TrackVector, reset all Conns & CLks
4784  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4785  {
4786  for(unsigned int y = 0; y < 4; y++)
4787  {
4788  TrackElementAt(1130, x).Conn[y] = -1;
4789  TrackElementAt(1131, x).ConnLinkPos[y] = -1;
4790  }
4791  }
4792  RebuildLocationNameMultiMap(1); // to ensure all position entries correct after track vector changes
4793  CheckMapAndTrack(4); // test
4794  CheckMapAndInactiveTrack(4); // test
4795  CheckLocationNameMultiMap(8); // test
4796  if(!ResetGapsFromGapMap(1))
4797  {
4798  Utilities->CallLogPop(489);
4799  return(false);
4800  }
4801  Utilities->CallLogPop(490);
4802  return(true);
4803 }
4804 
4805 // ---------------------------------------------------------------------------
4806 
4807 void TTrack::BuildGapMapFromTrackVector(int Caller) // Map contains one entry for each pair of matched gaps
4808 {
4809  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildGapMapFromTrackVector");
4810  GapMap.clear();
4811  THVPair GapMapKeyPair, GapMapValuePair;
4812  TGapMapEntry GapMapEntry;
4813 
4814  for(unsigned int x = 0; x < TrackVector.size(); x++)
4815  {
4816  if(TrackElementAt(1132, x).TrackType == GapJump)
4817  {
4818  GapMapKeyPair.first = TrackElementAt(1133, x).HLoc;
4819  GapMapKeyPair.second = TrackElementAt(1134, x).VLoc;
4820  GapMapEntry.first = GapMapKeyPair;
4821  if(TrackElementAt(1135, x).Conn[0] == -1)
4822  {
4823  throw Exception("Error - Gap connection == -1 Can't build GapMap");
4824  }
4825  GapMapValuePair.first = TrackElementAt(7, TrackElementAt(1136, x).Conn[0]).HLoc;
4826  GapMapValuePair.second = TrackElementAt(8, TrackElementAt(1137, x).Conn[0]).VLoc;
4827  GapMapEntry.second = GapMapValuePair;
4828  if(GapMap.find(GapMapValuePair) == GapMap.end()) // if ValuePair already included as a key then result won't be end()
4829  {
4830  GapMap.insert(GapMapEntry);
4831  }
4832  }
4833  }
4834  Utilities->CallLogPop(492);
4835 }
4836 
4837 // ---------------------------------------------------------------------------
4838 
4839 bool TTrack::LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
4840 {
4841  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrack," + AnsiString((short)FinalCall));
4842 
4843 //1st pass to check track element locations - split into 2 passes at v2.11.1 so positioning checked before linkages, requested by Dan(#4669) 18/12/21 via Discord
4844  LocError = false;
4845  bool TrackElementPositionsOK = true;
4846 
4847  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4848  {
4849  if(TrackElementAt(1138, x).TrackType == Erase) //Erase isn't used any more as a track type
4850  {
4851  continue; // skip blank elements
4852  }
4853 // check footcrossing linkages
4854  if(TrackElementAt(1139, x).TrackType == FootCrossing)
4855  {
4856  if(!CheckFootCrossingLinks(1, TrackElementAt(1140, x)))
4857  {
4858  ShowMessage(
4859  "Footbridge or underpass connection error. Each end must connect to a platform, concourse "
4860  "or other footbridge or underpass, and they can't connect to each other (i.e. a footbridge "
4861  "can't connect to an underpass or vice versa)");
4862  HLoc = TrackElementAt(1141, x).HLoc;
4863  VLoc = TrackElementAt(1142, x).VLoc;
4864  LocError = true;
4865  Utilities->CallLogPop(493);
4866  return(false);
4867  }
4868  }
4869  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4870  {
4871  if(TrackElementAt(1143, x).Link[y] <= 0)
4872  {
4873  continue; // no link
4874  }
4875  if((TrackElementAt(1144, x).TrackType == Buffers) && (TrackElementAt(1145, x).Config[y] == End))
4876  {
4877  continue; // buffer
4878  }
4879  if(TrackElementAt(1146, x).Config[y] == Gap)
4880  {
4881  continue; // gaps set later from GapMap
4882  }
4883  // get required H & V for track element joining link 'y'
4884  int NewHLoc = TrackElementAt(1437, x).HLoc + LinkHVArray[TrackElementAt(1148, x).Link[y]][0];
4885  int NewVLoc = TrackElementAt(1438, x).VLoc + LinkHVArray[TrackElementAt(1150, x).Link[y]][1];
4886  // find track element if present
4887  bool ConnectionFoundFlag;
4888  int VecPos = GetVectorPositionFromTrackMap(14, NewHLoc, NewVLoc, ConnectionFoundFlag);
4889  if((TrackElementAt(1151, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
4890  {
4891  ShowMessage("Can't have a track element adjacent to a continuation exit");
4892  HLoc = TrackElementAt(1152, x).HLoc;
4893  VLoc = TrackElementAt(1153, x).VLoc;
4894  LocError = true;
4895  if(FinalCall)
4896  {
4897  throw Exception("Error in final track linkage - continuation adjacent to another element");
4898  }
4899  Utilities->CallLogPop(1539);
4900  return(false);
4901  }
4902  if((TrackElementAt(1154, x).TrackType == Continuation) && (TrackElementAt(1155, x).Config[y] == End))
4903  {
4904  continue;
4905  }
4906  if(ConnectionFoundFlag)
4907  {
4908  TrackElementAt(1156, x).Conn[y] = VecPos; //<-- this sets the Conn value
4909  // find connecting link in the newly found track element if there is one & make buffer & adjacent signals check
4910  if((TrackElementAt(1157, x).Config[1 - y] == Signal) && IsLCAtHV(50, TrackElementAt(1158, VecPos).HLoc, TrackElementAt(1350, VecPos).VLoc))
4911  {
4912  // new in v2.4.0 - Krizar (Kristian Zarebski) found this error
4913  ShowMessage("Can't have an exit signal next to a level crossing - it can cause the train to foul the crossing in some circumstances");
4914  // otherwise when single route element removed in front of train the LC will start to close and the train will crash
4915  TrackElementPositionsOK = false;
4916  }
4917  else if(((TrackElementAt(1159, x).TrackType == Points) || (TrackElementAt(1160, x).TrackType == SignalPost) || (TrackElementAt(1161, x).TrackType == Crossover))
4918  && (TrackElementAt(1162, VecPos).TrackType == Buffers))
4919  {
4920  ShowMessage("Can't have points, crossover or signal next to buffers - need room for a train without fouling");
4921  // need room for a train (2 elements) without fouling points or signals
4922  TrackElementPositionsOK = false;
4923  }
4924  else if(((TrackElementAt(1163, x).TrackType == Points) || (TrackElementAt(1164, x).TrackType == SignalPost) || (TrackElementAt(1165, x).TrackType == Crossover) ||
4925  (TrackElementAt(1166, x).TrackType == Bridge)) && (TrackElementAt(1167, VecPos).TrackType == Continuation))
4926  {
4927  ShowMessage("Can't have points, crossover, bridge or signal next to a continuation - it can cause route setting problems");
4928  // route setting won't allow an end of route selection adjacent to an existing route, which would happen
4929  // if continuation next to a signal; also none of these can be a named location, and a continuation can
4930  // be named but needs the adjacent element named too
4931  TrackElementPositionsOK = false;
4932  }
4933  else if((TrackElementAt(1168, x).TrackType == SignalPost) && (TrackElementAt(1169, VecPos).TrackType == SignalPost) &&
4934  (TrackElementAt(1170, x).SpeedTag == TrackElementAt(1171, VecPos).SpeedTag))
4935  {
4936  ShowMessage("Can't have two same-direction signals adjacent to each other as there is no room for a train between them");
4937  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
4938  // selected - appears as trying to select a signal that is not the next in line from the starting signal
4939  TrackElementPositionsOK = false;
4940  }
4941  else if((TrackElementAt(1172, x).Config[y] == Signal) && (TrackElementAt(1173, VecPos).TrackType == Bridge) && !OverrideAndHideSignalBridgeMessage)
4942  {
4943  ShowMessage("Signal facing a bridge - routes can't be truncated to this or other such signals.\n\nThis restriction can be removed or reinstated by pressing\nCTRL ALT 5. When removed this message will not be shown again.");
4944  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
4945  // selected - appears as trying to select a signal that is not the next in line from the starting signal
4946  TrackElementPositionsOK = false;
4947  }
4948  else if(IsLCAtHV(45, TrackElementAt(1174, x).HLoc, TrackElementAt(1175, x).VLoc) && IsLCAtHV(46, TrackElementAt(1176, VecPos).HLoc, TrackElementAt(1177, VecPos).VLoc))
4949  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
4950  {
4951  ShowMessage("Can't have two level crossings adjacent to each other on the same track");
4952  TrackElementPositionsOK = false;
4953  }
4954  // if failed then set the invert values for the offending element
4955  if(!TrackElementPositionsOK)
4956  {
4957  HLoc = TrackElementAt(1183, x).HLoc;
4958  VLoc = TrackElementAt(1184, x).VLoc;
4959  LocError = true;
4960  if(FinalCall)
4961  {
4962  throw Exception("Error in track element positions in FinalCall");
4963  }
4964  Utilities->CallLogPop(494);
4965  return(false);
4966  }
4967  }
4968  // no 'else' here, if there's no link then will be picked up in 2nd pass
4969  }
4970  } // for(unsigned int x=0;x<TrackVector.size();x++)
4971 
4972 
4973 //2nd pass - looking for missing connections
4974  LocError = false;
4975  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4976  {
4977  if(TrackElementAt(1439, x).TrackType == Erase) //Erase isn't used any more as a track type
4978  {
4979  continue; // skip blank elements
4980  }
4981  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4982  {
4983  if(TrackElementAt(1440, x).Link[y] <= 0)
4984  {
4985  continue; // no link
4986  }
4987  if((TrackElementAt(1441, x).TrackType == Buffers) && (TrackElementAt(1442, x).Config[y] == End))
4988  {
4989  continue; // buffer
4990  }
4991  if(TrackElementAt(1443, x).Config[y] == Gap)
4992  {
4993  continue; // gaps set later from GapMap
4994  }
4995  if((TrackElementAt(1444, x).TrackType == Continuation) && (TrackElementAt(1445, x).Config[y] == End))
4996  {
4997  continue; //continuation
4998  }
4999  // get required H & V for track element joining link 'y'
5000  int NewHLoc = TrackElementAt(1147, x).HLoc + LinkHVArray[TrackElementAt(1448, x).Link[y]][0];
5001  int NewVLoc = TrackElementAt(1149, x).VLoc + LinkHVArray[TrackElementAt(1449, x).Link[y]][1];
5002  // find track element if present
5003  bool ConnectionFoundFlag;
5004  bool LinkMatchFound = false;
5005  int VecPos = GetVectorPositionFromTrackMap(66, NewHLoc, NewVLoc, ConnectionFoundFlag);
5006  // if there isn't a connection set the invert values for the offending element
5007  if(ConnectionFoundFlag) //set the ConnLinkPos values
5008  {
5009  for(unsigned int a = 0; a < 4; a++)
5010  {
5011  if((TrackElementAt(1178, VecPos).Link[a] == (10 - TrackElementAt(1179, x).Link[y])) && (TrackElementAt(1180, VecPos).Config[a] != End) &&
5012  (TrackElementAt(1181, VecPos).Config[a] != Gap))
5013  {
5014  TrackElementAt(1182, x).ConnLinkPos[y] = a;
5015  // note - this ensures that if the connecting element is a leading point
5016  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5017  // (Points have the same link value for both [0] and [2])
5018  LinkMatchFound = true;
5019  break; // stop after first find or will find later link for leading point
5020  }
5021  }
5022  if(!LinkMatchFound)
5023  {
5024  HLoc = TrackElementAt(1446, x).HLoc;
5025  VLoc = TrackElementAt(1447, x).VLoc;
5026  LocError = true;
5027  if(FinalCall)
5028  {
5029  throw Exception("Error in final track linkage - - no matching link found");
5030  }
5031  Utilities->CallLogPop(495);
5032  return(false);
5033  }
5034  }
5035  else //error
5036  {
5037  HLoc = TrackElementAt(1185, x).HLoc;
5038  VLoc = TrackElementAt(1186, x).VLoc;
5039  LocError = true;
5040  if(FinalCall)
5041  {
5042  throw Exception("Error in final track linkage - connection not found");
5043  }
5044  Utilities->CallLogPop(2443);
5045  return(false);
5046  }
5047  }
5048  }
5049 //end of 2nd pass
5050 
5051  if(FinalCall)
5052  {
5054  }
5055 
5056 // confirmatiory checks that all ok - or throw error
5057  bool ConnErrorFlag = false;
5058 
5059  for(unsigned int x = 0; x < TrackVector.size(); x++)
5060  {
5061  if((TrackElementAt(1187, x).Link[0] > 0) && (TrackElementAt(1188, x).Config[0] != End) && (TrackElementAt(1189, x).Conn[0] == -1))
5062  {
5063  ConnErrorFlag = true;
5064  }
5065  if((TrackElementAt(1190, x).Link[1] > 0) && (TrackElementAt(1191, x).Config[1] != End) && (TrackElementAt(1192, x).Conn[1] == -1))
5066  {
5067  ConnErrorFlag = true;
5068  }
5069  if((TrackElementAt(1193, x).Link[2] > 0) && (TrackElementAt(1194, x).Config[2] != End) && (TrackElementAt(1195, x).Conn[2] == -1))
5070  {
5071  ConnErrorFlag = true;
5072  }
5073  if((TrackElementAt(1196, x).Link[3] > 0) && (TrackElementAt(1197, x).Config[3] != End) && (TrackElementAt(1198, x).Conn[3] == -1))
5074  {
5075  ConnErrorFlag = true;
5076  }
5077  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
5078  {
5079  if(TrackElementAt(1199, x).ActiveTrackElementName == "")
5080  {
5081  if((TrackElementAt(1200, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1201, x).StationEntryStopLinkPos2 != -1))
5082  {
5083  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
5084  }
5085  }
5086  }
5087  }
5088  if(ConnErrorFlag)
5089  {
5090  if(FinalCall)
5091  {
5092  throw Exception("ConnError in LinkTrack - Final");
5093  }
5094  else
5095  {
5096  throw Exception("ConnError in LinkTrack - Precheck");
5097  }
5098  }
5099  bool CLkErrorFlag = false;
5100 
5101  for(unsigned int x = 0; x < TrackVector.size(); x++)
5102  {
5103  if((TrackElementAt(1202, x).Link[0] > 0) && (TrackElementAt(1203, x).Config[0] != End) && (TrackElementAt(1204, x).ConnLinkPos[0] == -1))
5104  {
5105  CLkErrorFlag = true;
5106  }
5107  if((TrackElementAt(1205, x).Link[1] > 0) && (TrackElementAt(1206, x).Config[1] != End) && (TrackElementAt(1207, x).ConnLinkPos[1] == -1))
5108  {
5109  CLkErrorFlag = true;
5110  }
5111  if((TrackElementAt(1208, x).Link[2] > 0) && (TrackElementAt(1209, x).Config[2] != End) && (TrackElementAt(1210, x).ConnLinkPos[2] == -1))
5112  {
5113  CLkErrorFlag = true;
5114  }
5115  if((TrackElementAt(1211, x).Link[3] > 0) && (TrackElementAt(1212, x).Config[3] != End) && (TrackElementAt(1213, x).ConnLinkPos[3] == -1))
5116  {
5117  CLkErrorFlag = true;
5118  }
5119  }
5120 
5121  if(CLkErrorFlag)
5122  {
5123  if(FinalCall)
5124  {
5125  throw Exception("CLkError in LinkTrack - Final");
5126  }
5127  else
5128  {
5129  throw Exception("CLkError in LinkTrack - Precheck");
5130  }
5131  }
5132 
5133 // set element lengths to min of 10m
5134  for(unsigned int x = 0; x < TrackVector.size(); x++)
5135  {
5136  if(TrackElementAt(1214, x).TrackType == Erase)
5137  {
5138  continue; // skip blank elements
5139  }
5140  if((TrackElementAt(1215, x).Length01 < 10) && (TrackElementAt(1435, x).Length01 != -1))
5141  {
5142  TrackElementAt(1216, x).Length01 = 10;
5143  }
5144  if((TrackElementAt(1217, x).Length23 < 10) && (TrackElementAt(1218, x).Length23 != -1))
5145  {
5146  TrackElementAt(1219, x).Length23 = 10;
5147  }
5148  }
5149 
5150  if(FinalCall) // ONLY at FinalCall, no point calling twice
5151  {
5152  CalcHLocMinEtc(3);
5153  }
5154 
5155  Utilities->CallLogPop(497);
5156  return(true);
5157 }
5158 
5159 // ---------------------------------------------------------------------------
5160 
5161 bool TTrack::LinkTrackNoMessages(int Caller, bool FinalCall)
5162 {
5163  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrackNoMessages," + AnsiString((short)FinalCall));
5164  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5165  {
5166  if(TrackElementAt(1220, x).TrackType == Erase)
5167  {
5168  continue; // skip blank elements
5169 
5170  }
5171 // check footcrossing linkages
5172  if(TrackElementAt(1221, x).TrackType == FootCrossing)
5173  {
5174  if(!CheckFootCrossingLinks(3, TrackElementAt(1222, x)))
5175  {
5176  Utilities->CallLogPop(1127);
5177  return(false);
5178  }
5179  }
5180  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5181  {
5182  if(TrackElementAt(1223, x).Link[y] <= 0)
5183  {
5184  continue; // no link
5185  }
5186  if((TrackElementAt(1224, x).TrackType == Buffers) && (TrackElementAt(1225, x).Config[y] == End))
5187  {
5188  continue; // buffer
5189  }
5190  if(TrackElementAt(1226, x).Config[y] == Gap)
5191  {
5192  continue; // gaps set later from GapMap
5193 
5194  }
5195  // get required H & V for track element joining link 'y'
5196  int NewHLoc = TrackElementAt(1227, x).HLoc + LinkHVArray[TrackElementAt(1228, x).Link[y]][0];
5197  int NewVLoc = TrackElementAt(1229, x).VLoc + LinkHVArray[TrackElementAt(1230, x).Link[y]][1];
5198  // find track element if present
5199  bool ConnectionFoundFlag;
5200  int VecPos = GetVectorPositionFromTrackMap(38, NewHLoc, NewVLoc, ConnectionFoundFlag);
5201  if((TrackElementAt(1231, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
5202  {
5203  if(FinalCall)
5204  {
5205  throw Exception("Error in final track linkage - continuation adjacent to another element");
5206  }
5207  Utilities->CallLogPop(1540);
5208  return(false);
5209  }
5210  if((TrackElementAt(1232, x).TrackType == Continuation) && (TrackElementAt(1233, x).Config[y] == End))
5211  {
5212  continue;
5213  }
5214  if(ConnectionFoundFlag)
5215  {
5216  TrackElementAt(1234, x).Conn[y] = VecPos;
5217  bool LinkFoundFlag = false;
5218  // find connecting link in the newly found track element if there is one & make checks
5219  if(((TrackElementAt(1235, x).TrackType == Points) || (TrackElementAt(1236, x).TrackType == SignalPost) || (TrackElementAt(1237, x).TrackType == Crossover)) &&
5220  (TrackElementAt(1238, VecPos).TrackType == Buffers))
5221  {
5222  Utilities->CallLogPop(1541);
5223  return(false);
5224  }
5225  else if(((TrackElementAt(1239, x).TrackType == Points) || (TrackElementAt(1240, x).TrackType == SignalPost) || (TrackElementAt(1241, x).TrackType == Crossover) ||
5226  (TrackElementAt(1242, x).TrackType == Bridge)) && (TrackElementAt(1243, VecPos).TrackType == Continuation))
5227  {
5228  Utilities->CallLogPop(1542);
5229  return(false);
5230  }
5231  else if((TrackElementAt(1244, x).TrackType == SignalPost) && (TrackElementAt(1245, VecPos).TrackType == SignalPost) &&
5232  (TrackElementAt(1246, x).SpeedTag == TrackElementAt(1247, VecPos).SpeedTag))
5233  {
5234  Utilities->CallLogPop(1543);
5235  return(false);
5236  }
5237  else if(IsLCAtHV(47, TrackElementAt(1248, x).HLoc, TrackElementAt(1249, x).VLoc) && IsLCAtHV(48, TrackElementAt(1250, VecPos).HLoc, TrackElementAt(1251, VecPos).VLoc))
5238  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
5239  {
5240  Utilities->CallLogPop(1981);
5241  return(false);
5242  }
5243 /* remove this restriction now that not permitted to treat a named continuation as a location stop
5244  else if(TrackElementAt(, x).TrackType == Continuation)
5245  {
5246  int H = TrackElementAt(, x).HLoc;
5247  int V = TrackElementAt(, x).VLoc;
5248  bool FoundFlag = false;
5249  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(18, H, V, FoundFlag);
5250  if(FoundFlag)
5251  {
5252  if(InactiveTrackElementAt(93, IMPair.first).TrackType == NamedNonStationLocation)
5253  {
5254  int NewH = TrackElementAt(, (TrackElementAt(, x).Conn[1])).HLoc;
5255  int NewV = TrackElementAt(, (TrackElementAt(, x).Conn[1])).VLoc;
5256  TIMPair NewIMPair = GetVectorPositionsFromInactiveTrackMap(19, NewH, NewV, FoundFlag);
5257  if(FoundFlag)
5258  {
5259  if(InactiveTrackElementAt(94, NewIMPair.first).TrackType != NamedNonStationLocation)
5260  {
5261  Utilities->CallLogPop();
5262  return false;
5263  }
5264  }
5265  else
5266  {
5267  Utilities->CallLogPop();
5268  return false;
5269  }
5270  }
5271  }
5272  }
5273 */
5274  for(unsigned int a = 0; a < 4; a++)
5275  {
5276  if((TrackElementAt(1252, VecPos).Link[a] == (10 - TrackElementAt(1253, x).Link[y])) && (TrackElementAt(1254, VecPos).Config[a] != End) &&
5277  (TrackElementAt(1255, VecPos).Config[a] != Gap))
5278  {
5279  TrackElementAt(1256, x).ConnLinkPos[y] = a;
5280  // note - this ensures that if the connecting element is a leading point
5281  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5282  // (Points have the same link value for both [0] and [2])
5283  LinkFoundFlag = true;
5284  break; // stop after first find or will find later link for leading point
5285  }
5286  }
5287  if(!LinkFoundFlag)
5288  {
5289  if(FinalCall)
5290  {
5291  throw Exception("Error in final track linkage in LinkTrackNoMessages - invalid link");
5292  }
5293  Utilities->CallLogPop(1128);
5294  return(false);
5295  }
5296  }
5297  else // if(ConnectionFoundFlag)
5298  {
5299  if(FinalCall)
5300  {
5301  throw Exception("Error in final track linkage in LinkTrackNoMessages - connection not found");
5302  }
5303  Utilities->CallLogPop(1129);
5304  return(false);
5305  }
5306  }
5307  } // for(unsigned int x=0;x<TrackVector.size();x++)
5308 
5309  if(FinalCall)
5310  {
5312  }
5313 // final check
5314  bool ConnErrorFlag = false;
5315 
5316  for(unsigned int x = 0; x < TrackVector.size(); x++)
5317  {
5318  if((TrackElementAt(1257, x).Link[0] > 0) && (TrackElementAt(1258, x).Config[0] != End) && (TrackElementAt(1259, x).Conn[0] == -1))
5319  {
5320  ConnErrorFlag = true;
5321  }
5322  if((TrackElementAt(1260, x).Link[1] > 0) && (TrackElementAt(1261, x).Config[1] != End) && (TrackElementAt(1262, x).Conn[1] == -1))
5323  {
5324  ConnErrorFlag = true;
5325  }
5326  if((TrackElementAt(1263, x).Link[2] > 0) && (TrackElementAt(1264, x).Config[2] != End) && (TrackElementAt(1265, x).Conn[2] == -1))
5327  {
5328  ConnErrorFlag = true;
5329  }
5330  if((TrackElementAt(1266, x).Link[3] > 0) && (TrackElementAt(1267, x).Config[3] != End) && (TrackElementAt(1268, x).Conn[3] == -1))
5331  {
5332  ConnErrorFlag = true;
5333  }
5334  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
5335  {
5336  if(TrackElementAt(1269, x).ActiveTrackElementName == "")
5337  {
5338  if((TrackElementAt(1270, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1271, x).StationEntryStopLinkPos2 != -1))
5339  {
5340  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
5341  }
5342  }
5343  }
5344  }
5345  if(ConnErrorFlag)
5346  {
5347  if(FinalCall)
5348  {
5349  throw Exception("ConnError in LinkTrack - Final");
5350  }
5351  else
5352  {
5353  throw Exception("ConnError in LinkTrack - Precheck");
5354  }
5355  }
5356  bool CLkErrorFlag = false;
5357 
5358  for(unsigned int x = 0; x < TrackVector.size(); x++)
5359  {
5360  if((TrackElementAt(1272, x).Link[0] > 0) && (TrackElementAt(1273, x).Config[0] != End) && (TrackElementAt(1274, x).ConnLinkPos[0] == -1))
5361  {
5362  CLkErrorFlag = true;
5363  }
5364  if((TrackElementAt(1275, x).Link[1] > 0) && (TrackElementAt(1276, x).Config[1] != End) && (TrackElementAt(1277, x).ConnLinkPos[1] == -1))
5365  {
5366  CLkErrorFlag = true;
5367  }
5368  if((TrackElementAt(1278, x).Link[2] > 0) && (TrackElementAt(1279, x).Config[2] != End) && (TrackElementAt(1280, x).ConnLinkPos[2] == -1))
5369  {
5370  CLkErrorFlag = true;
5371  }
5372  if((TrackElementAt(1281, x).Link[3] > 0) && (TrackElementAt(1282, x).Config[3] != End) && (TrackElementAt(1283, x).ConnLinkPos[3] == -1))
5373  {
5374  CLkErrorFlag = true;
5375  }
5376  }
5377 
5378  if(CLkErrorFlag)
5379  {
5380  if(FinalCall)
5381  {
5382  throw Exception("CLkError in LinkTrack - Final");
5383  }
5384  else
5385  {
5386  throw Exception("CLkError in LinkTrack - Precheck");
5387  }
5388  }
5389 // set element lengths to min of 10m
5390  for(unsigned int x = 0; x < TrackVector.size(); x++)
5391  {
5392  if(TrackElementAt(1284, x).TrackType == Erase)
5393  {
5394  continue; // skip blank elements
5395  }
5396  if((TrackElementAt(1285, x).Length01 < 10) && (TrackElementAt(1436, x).Length23 != -1))
5397  {
5398  TrackElementAt(1286, x).Length01 = 10;
5399  }
5400  if((TrackElementAt(1287, x).Length23 < 10) && (TrackElementAt(1288, x).Length23 != -1))
5401  {
5402  TrackElementAt(1289, x).Length23 = 10;
5403  }
5404  }
5405 
5406  if(FinalCall) // ONLY at FinalCall, no point calling twice
5407  {
5408  CalcHLocMinEtc(7);
5409  }
5410  Utilities->CallLogPop(1130);
5411  return(true);
5412 }
5413 
5414 // ---------------------------------------------------------------------------
5415 
5416 bool TTrack::IsTrackLinked(int Caller) // not used any more
5417 {
5418  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsTrackLinked");
5419  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5420  {
5421  if(TrackElementAt(1290, x).TrackType == Erase)
5422  {
5423  Utilities->CallLogPop(498);
5424  return(false);
5425  }
5426 // check foot linkages
5427  if(TrackElementAt(1291, x).TrackType == FootCrossing)
5428  {
5429  if(!CheckFootCrossingLinks(2, TrackElementAt(1292, x)))
5430  {
5431  Utilities->CallLogPop(499);
5432  return(false);
5433  }
5434  }
5435  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5436  {
5437  if(TrackElementAt(1293, x).Link[y] <= 0)
5438  {
5439  continue; // no link
5440  }
5441  if(TrackElementAt(1294, x).Config[y] == End)
5442  {
5443  continue; // buffer or continuation
5444  }
5445  if(TrackElementAt(1295, x).Config[y] == Gap)
5446  {
5447  continue; // gaps set later from GapMap
5448 
5449  }
5450  // get required H & V for track element joining link 'y'
5451  int NewHLoc = TrackElementAt(1296, x).HLoc + LinkHVArray[TrackElementAt(1297, x).Link[y]][0];
5452  int NewVLoc = TrackElementAt(1298, x).VLoc + LinkHVArray[TrackElementAt(1299, x).Link[y]][1];
5453  // find track element if present
5454  bool ConnectionFoundFlag = false;
5455  int VecPos = GetVectorPositionFromTrackMap(15, NewHLoc, NewVLoc, ConnectionFoundFlag);
5456  if(ConnectionFoundFlag)
5457  {
5458  TrackElementAt(1300, x).Conn[y] = VecPos;
5459  // find connecting link in the newly found track element if there is one & make buffer check
5460  bool LinkFoundFlag = false;
5461  if(((TrackElementAt(1301, x).TrackType == Points) || (TrackElementAt(1302, x).TrackType == SignalPost) || (TrackElementAt(1303, x).TrackType == Crossover)) &&
5462  (TrackElementAt(1304, VecPos).TrackType == Buffers))
5463  {
5464  Utilities->CallLogPop(500);
5465  return(false);
5466  }
5467  else if((TrackElementAt(1305, x).TrackType == SignalPost) && (TrackElementAt(1306, VecPos).TrackType == SignalPost) &&
5468  (TrackElementAt(1307, x).SpeedTag == TrackElementAt(1308, VecPos).SpeedTag))
5469  {
5470  Utilities->CallLogPop(501);
5471  return(false);
5472  }
5473  else if((TrackElementAt(1309, x).TrackType == SignalPost) && (TrackElementAt(1310, VecPos).TrackType == Continuation))
5474  {
5475  Utilities->CallLogPop(502);
5476  return(false);
5477  }
5478  else
5479  {
5480  for(unsigned int a = 0; a < 4; a++)
5481  {
5482  if((TrackElementAt(1311, VecPos).Link[a] == (10 - TrackElementAt(1312, x).Link[y])) && (TrackElementAt(1313, VecPos).Config[a] != End) &&
5483  (TrackElementAt(1314, VecPos).Config[a] != Gap))
5484  {
5485  TrackElementAt(1315, x).ConnLinkPos[y] = a;
5486  // note - this ensures that if the connecting element is a leading point
5487  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5488  // (Points have the same link value for both [0] and [2])
5489  LinkFoundFlag = true;
5490  break; // stop after first find or will find later link for leading point
5491  }
5492  }
5493  }
5494  if(!LinkFoundFlag)
5495  {
5496  Utilities->CallLogPop(503);
5497  return(false);
5498  }
5499  }
5500  else // if(ConnectionFoundFlag)
5501  {
5502  Utilities->CallLogPop(504);
5503  return(false);
5504  }
5505  }
5506  } // for(unsigned int x=0;x<TrackVector.size();x++)
5507 
5508 // final check
5509  bool ConnErrorFlag = false;
5510 
5511  for(unsigned int x = 0; x < TrackVector.size(); x++)
5512  {
5513  if((TrackElementAt(1316, x).Link[0] > 0) && (TrackElementAt(1317, x).Config[0] != End) && (TrackElementAt(1318, x).Conn[0] == -1))
5514  {
5515  ConnErrorFlag = true;
5516  }
5517  if((TrackElementAt(1319, x).Link[1] > 0) && (TrackElementAt(1320, x).Config[1] != End) && (TrackElementAt(1321, x).Conn[1] == -1))
5518  {
5519  ConnErrorFlag = true;
5520  }
5521  if((TrackElementAt(1322, x).Link[2] > 0) && (TrackElementAt(1333, x).Config[2] != End) && (TrackElementAt(1334, x).Conn[2] == -1))
5522  {
5523  ConnErrorFlag = true;
5524  }
5525  if((TrackElementAt(1335, x).Link[3] > 0) && (TrackElementAt(1336, x).Config[3] != End) && (TrackElementAt(1337, x).Conn[3] == -1))
5526  {
5527  ConnErrorFlag = true;
5528  }
5529  }
5530  if(ConnErrorFlag)
5531  {
5532  Utilities->CallLogPop(505);
5533  return(false);
5534  }
5535  bool CLkErrorFlag = false;
5536 
5537  for(unsigned int x = 0; x < TrackVector.size(); x++)
5538  {
5539  if((TrackElementAt(1338, x).Link[0] > 0) && (TrackElementAt(1339, x).Config[0] != End) && (TrackElementAt(1340, x).ConnLinkPos[0] == -1))
5540  {
5541  CLkErrorFlag = true;
5542  }
5543  if((TrackElementAt(1341, x).Link[1] > 0) && (TrackElementAt(1342, x).Config[1] != End) && (TrackElementAt(1343, x).ConnLinkPos[1] == -1))
5544  {
5545  CLkErrorFlag = true;
5546  }
5547  if((TrackElementAt(1344, x).Link[2] > 0) && (TrackElementAt(1345, x).Config[2] != End) && (TrackElementAt(1346, x).ConnLinkPos[2] == -1))
5548  {
5549  CLkErrorFlag = true;
5550  }
5551  if((TrackElementAt(1347, x).Link[3] > 0) && (TrackElementAt(1394, x).Config[3] != End) && (TrackElementAt(1348, x).ConnLinkPos[3] == -1))
5552  {
5553  CLkErrorFlag = true;
5554  }
5555  }
5556 
5557  if(CLkErrorFlag)
5558  {
5559  Utilities->CallLogPop(506);
5560  return(false);
5561  }
5562  Utilities->CallLogPop(507);
5563  return(true);
5564 }
5565 
5566 // ---------------------------------------------------------------------------
5567 
5569 {
5570  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetGapsFromGapMap");
5571  int Position1, Position2;
5572  TTrackElement TrackElement1, TrackElement2;
5573  TGapMapIterator GapMapPtr;
5574 
5575  if(!GapMap.empty())
5576  {
5577  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
5578  {
5579  int HLoc1 = GapMapPtr->first.first;
5580  int VLoc1 = GapMapPtr->first.second;
5581  int HLoc2 = GapMapPtr->second.first;
5582  int VLoc2 = GapMapPtr->second.second;
5583  if(!FindNonPlatformMatch(12, HLoc1, VLoc1, Position1, TrackElement1))
5584  {
5585  throw Exception("Failed to find H & V for gap1, GapMap in error");
5586  }
5587  if(!FindNonPlatformMatch(13, HLoc2, VLoc2, Position2, TrackElement2))
5588  {
5589  throw Exception("Failed to find H & V for gap2, GapMap in error");
5590  }
5591  if(TrackElementAt(9, Position1).TrackType != GapJump)
5592  {
5593  throw Exception("Element at Pos1 not a gap, GapMap in error");
5594  }
5595  if(TrackElementAt(10, Position2).TrackType != GapJump)
5596  {
5597  throw Exception("Element at Pos2 not a gap, GapMap in error");
5598  }
5599  TrackElementAt(11, Position1).Conn[0] = Position2;
5600  TrackElementAt(12, Position1).ConnLinkPos[0] = 0;
5601  TrackElementAt(13, Position2).Conn[0] = Position1;
5602  TrackElementAt(14, Position2).ConnLinkPos[0] = 0;
5603  }
5604  }
5605  Utilities->CallLogPop(510);
5606  return(true);
5607 }
5608 
5609 // ---------------------------------------------------------------------------
5610 
5611 void TTrack::TrackPush(int Caller, TTrackElement TrackElement)
5612 {
5613 // TIMPair MapEntry;
5614  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackPush," + AnsiString(TrackElement.HLoc) + "," +
5615  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
5616  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
5617  TTrackMapEntry TrackMapEntry, InactiveTrackMapEntry;
5618  TLocationNameMultiMapEntry LocationNameEntry;
5619 
5620  LocationNameEntry.first = TrackElement.LocationName;
5621  if((TrackElement.TrackType == Platform) || (TrackElement.TrackType == Concourse) || (TrackElement.TrackType == Parapet) ||
5622  (TrackElement.TrackType == NamedNonStationLocation) || (TrackElement.TrackType == LevelCrossing))
5623  {
5624 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5625 // could arise when loading old railways with multiple NonStationNamedLocs
5626  bool FoundFlag = false;
5627  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(20, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5628  if(FoundFlag)
5629  {
5630  if((InactiveTrackElementAt(97, IMPair.first).SpeedTag == TrackElement.SpeedTag) || (InactiveTrackElementAt(98,
5631  IMPair.second).SpeedTag == TrackElement.SpeedTag))
5632  {
5633  Utilities->CallLogPop(1813);
5634  return;
5635  }
5636  }
5637  InactiveTrackVector.push_back(TrackElement); // no erase elements involved in InactiveTrackVector
5638  InactiveTrackMapKeyPair.first = TrackElement.HLoc;
5639  InactiveTrackMapKeyPair.second = TrackElement.VLoc;
5640  InactiveTrackMapEntry.first = InactiveTrackMapKeyPair;
5641  InactiveTrackMapEntry.second = InactiveTrackVector.size() - 1;
5642  InactiveTrack2MultiMap.insert(InactiveTrackMapEntry);
5643  if(TrackElement.FixedNamedLocationElement)
5644  {
5645  LocationNameEntry.second = InactiveTrackVector.size() - 1; // add to LocationNameMultiMap
5646  LocationNameMultiMap.insert(LocationNameEntry);
5647  }
5648  if(TrackElement.HLoc < HLocMin)
5649  {
5650  HLocMin = TrackElement.HLoc;
5651  }
5652  if(TrackElement.HLoc > HLocMax)
5653  {
5654  HLocMax = TrackElement.HLoc;
5655  }
5656  if(TrackElement.VLoc < VLocMin)
5657  {
5658  VLocMin = TrackElement.VLoc;
5659  }
5660  if(TrackElement.VLoc > VLocMax)
5661  {
5662  VLocMax = TrackElement.VLoc;
5663  }
5664  }
5665  else
5666  {
5667 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5668 // shouldn't arise but leave in as a safeguard
5669  bool FoundFlag = false;
5670  int VecPos = GetVectorPositionFromTrackMap(44, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5671  if(FoundFlag)
5672  {
5673  if(TrackElementAt(816, VecPos).SpeedTag == TrackElement.SpeedTag)
5674  {
5675  Utilities->CallLogPop(1814);
5676  return;
5677  }
5678  }
5679  TrackVector.push_back(TrackElement); // add erase elements to vector to keep linkages correct (now dispensed with)
5680  if(TrackElement.TrackType != Erase) // don't add erase elements to TrackMap (dispensed with these but keep code)
5681  {
5682  TrackMapKeyPair.first = TrackElement.HLoc;
5683  TrackMapKeyPair.second = TrackElement.VLoc;
5684  TrackMapEntry.first = TrackMapKeyPair;
5685  TrackMapEntry.second = TrackVector.size() - 1;
5686  TrackMap.insert(TrackMapEntry);
5687  if(TrackElement.FixedNamedLocationElement)
5688  {
5689  LocationNameEntry.second = -(int)(TrackVector.size()); // add to LocationNameMultiMap TrackVector.size = Required value + 1, so ...second = -1-Requ'd value
5690  LocationNameMultiMap.insert(LocationNameEntry);
5691  }
5692  if(TrackElement.HLoc < HLocMin)
5693  {
5694  HLocMin = TrackElement.HLoc; // exclude erase elements as HLoc & VLoc set to -2000000000
5695  }
5696  if(TrackElement.HLoc > HLocMax)
5697  {
5698  HLocMax = TrackElement.HLoc;
5699  }
5700  if(TrackElement.VLoc < VLocMin)
5701  {
5702  VLocMin = TrackElement.VLoc;
5703  }
5704  if(TrackElement.VLoc > VLocMax)
5705  {
5706  VLocMax = TrackElement.VLoc;
5707  }
5708  }
5709  }
5710 // CheckMapAndTrack(6);//test drop these to speed up, still checked outside this function
5711 // CheckMapAndInactiveTrack(6);//test
5712 
5713 // CheckLocationNameMultiMap(14);//test Can't test here as when loading the ActiveTrackElementName elements will be out of step
5714 // with the Platforms until layout fully loaded
5715  Utilities->CallLogPop(511);
5716 }
5717 
5718 // ---------------------------------------------------------------------------
5719 
5720 int TTrack::GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5721 {
5722  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionFromTrackMap," + AnsiString(HLoc) + "," +
5723  AnsiString(VLoc));
5724  THVPair TrackMapKeyPair;
5725 
5726  FoundFlag = false;
5727  TTrackMapIterator TrackMapPtr;
5728 
5729  TrackMapKeyPair.first = HLoc;
5730  TrackMapKeyPair.second = VLoc;
5731  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5732  if(TrackMapPtr == TrackMap.end())
5733  {
5734  Utilities->CallLogPop(512);
5735  return(-1); // nothing found
5736  }
5737  else
5738  {
5739  FoundFlag = true;
5740  Utilities->CallLogPop(513);
5741  return(TrackMapPtr->second);
5742  }
5743 }
5744 
5745 // ---------------------------------------------------------------------------
5746 
5747 TTrackElement &TTrack::GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
5748 {
5749  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5750  AnsiString(VLoc));
5751  THVPair TrackMapKeyPair;
5752  TTrackMapIterator TrackMapPtr;
5753 
5754  TrackMapKeyPair.first = HLoc;
5755  TrackMapKeyPair.second = VLoc;
5756  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5757  if(TrackMapPtr == TrackMap.end())
5758  {
5759  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5760  throw Exception(Message);
5761  }
5762  else
5763  {
5764  Utilities->CallLogPop(1943);
5765  return(TrackElementAt(871, TrackMapPtr->second));
5766  }
5767 }
5768 
5769 // ---------------------------------------------------------------------------
5770 
5771 TTrackElement &TTrack::GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector) //new at v2.9.0 for clipboard pref dirs
5772 { //modded at v2.9.2 to make Map & Vector references
5773  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromAnyTrackMap," + AnsiString(HLoc) + "," +
5774  AnsiString(VLoc));
5775  THVPair MapKeyPair;
5776  TTrackMapIterator MapPtr;
5777 
5778  MapKeyPair.first = HLoc;
5779  MapKeyPair.second = VLoc;
5780  MapPtr = Map.find(MapKeyPair);
5781  if(MapPtr == Map.end())
5782  {
5783  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc) + " in GetTrackElementFromAnyTrackMap";
5784  throw Exception(Message);
5785  }
5786  else
5787  {
5788  Utilities->CallLogPop(2280);
5789  return(Vector.at(MapPtr->second));
5790  }
5791 }
5792 
5793 // ---------------------------------------------------------------------------
5794 
5796 {
5797  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetInactiveTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5798  AnsiString(VLoc));
5799  THVPair InactiveTrackMapKeyPair;
5800  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5801 
5802  InactiveTrackMapKeyPair.first = HLoc;
5803  InactiveTrackMapKeyPair.second = VLoc;
5804  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5805  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5806  {
5807  AnsiString Message = "Inactive element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5808  throw Exception(Message);
5809  }
5810  else
5811  {
5812  Utilities->CallLogPop(1949);
5813  return(InactiveTrackElementAt(34, InactiveTrackMapPtr->second));
5814  }
5815 }
5816 
5817 // ---------------------------------------------------------------------------
5818 
5819 bool TTrack::TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5820 {
5821  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementPresentAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5822  bool Present = true;
5823  THVPair TrackMapKeyPair;
5824  TTrackMapIterator TrackMapPtr;
5825 
5826  TrackMapKeyPair.first = HLoc;
5827  TrackMapKeyPair.second = VLoc;
5828  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5829  if(TrackMapPtr == TrackMap.end())
5830  {
5831  Present = false;
5832  }
5833  Utilities->CallLogPop(2057);
5834  return(Present);
5835 }
5836 
5837 // ---------------------------------------------------------------------------
5838 
5839 bool TTrack::InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5840 {
5841  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementPresentAtHV," + AnsiString(HLoc) + "," +
5842  AnsiString(VLoc));
5843  bool Present = true;
5844  THVPair InactiveTrackMapKeyPair;
5845  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5846 
5847  InactiveTrackMapKeyPair.first = HLoc;
5848  InactiveTrackMapKeyPair.second = VLoc;
5849  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5850  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5851  {
5852  Present = false;
5853  }
5854  Utilities->CallLogPop(2058);
5855  return(Present);
5856 }
5857 
5858 // ---------------------------------------------------------------------------
5859 
5860 TTrack::TIMPair TTrack::GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5861 // max number of elements is 2, for platforms
5862 // note that both elements of RetPair may be the same, if only one present in map
5863 {
5864  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromInactiveTrackMap," + AnsiString(HLoc) + "," +
5865  AnsiString(VLoc));
5866  THVPair InactiveTrackMapKeyPair;
5867  TIMPair RetPair;
5868  TInactiveTrackRange InactiveTrackRange;
5869 
5870  FoundFlag = false;
5871  InactiveTrackMapKeyPair.first = HLoc;
5872  InactiveTrackMapKeyPair.second = VLoc;
5873  if(InactiveTrack2MultiMap.empty())
5874  {
5875  RetPair.first = 0;
5876  RetPair.second = 0;
5877  Utilities->CallLogPop(1815);
5878  return(RetPair); // map empty
5879  }
5880  InactiveTrackRange = InactiveTrack2MultiMap.equal_range(InactiveTrackMapKeyPair);
5881  if(InactiveTrackRange.first == InactiveTrackRange.second)
5882  {
5883  RetPair.first = 0;
5884  RetPair.second = 0;
5885  Utilities->CallLogPop(514);
5886  return(RetPair); // nothing found
5887  }
5888  else
5889  {
5890  RetPair.first = InactiveTrackRange.first->second;
5891  RetPair.second = (--InactiveTrackRange.second)->second;
5892  FoundFlag = true;
5893  Utilities->CallLogPop(515);
5894  return(RetPair);
5895  }
5896 }
5897 
5898 // ---------------------------------------------------------------------------
5899 
5900 bool TTrack::MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition) //changed at v2.13.0 to return true for failed but matching points
5901 {
5902 // only change where have adjacent points with their diverging links connected - not appropriate for non-straight points
5903  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MatchingPoint," + AnsiString(TrackVectorPosition) + "," +
5904  AnsiString(DivergingPosition));
5905  TTrackElement T1 = TrackElementAt(15, TrackVectorPosition);
5906  TTrackElement T2 = TrackElementAt(16, DivergingPosition);
5907  int SpeedTag1 = T1.SpeedTag;
5908  int SpeedTag2 = T2.SpeedTag;
5909 
5910  if((T1.Attribute) != (T2.Attribute))
5911  {
5912  Utilities->CallLogPop(516);
5913  return(false);
5914  }
5915  if(((SpeedTag1 == 7) && (SpeedTag2 == 10)) || // straight track hor, diverging track vert
5916  ((SpeedTag1 == 10) && (SpeedTag2 == 7)) || ((SpeedTag1 == 8) && (SpeedTag2 == 9)) || ((SpeedTag1 == 9) && (SpeedTag2 == 8)) ||
5917  ((SpeedTag1 == 11) && (SpeedTag2 == 14)) || // straight track vert, diverging track hor
5918  ((SpeedTag1 == 14) && (SpeedTag2 == 11)) || ((SpeedTag1 == 12) && (SpeedTag2 == 13)) || ((SpeedTag1 == 13) && (SpeedTag2 == 12)) ||
5919  ((SpeedTag1 == 28) && (SpeedTag2 == 31)) || // straight track hor, diverging track 45 deg
5920  ((SpeedTag1 == 31) && (SpeedTag2 == 28)) || ((SpeedTag1 == 29) && (SpeedTag2 == 30)) || ((SpeedTag1 == 30) && (SpeedTag2 == 29)) ||
5921  ((SpeedTag1 == 32) && (SpeedTag2 == 35)) || // straight track vert, diverging track 45 deg
5922  ((SpeedTag1 == 35) && (SpeedTag2 == 32)) || ((SpeedTag1 == 33) && (SpeedTag2 == 34)) || ((SpeedTag1 == 34) && (SpeedTag2 == 33)) ||
5923  ((SpeedTag1 == 36) && (SpeedTag2 == 39)) || // straight track 45 deg, diverging track vert
5924  ((SpeedTag1 == 39) && (SpeedTag2 == 36)) || ((SpeedTag1 == 37) && (SpeedTag2 == 38)) || ((SpeedTag1 == 38) && (SpeedTag2 == 37)) ||
5925  ((SpeedTag1 == 40) && (SpeedTag2 == 43)) || // straight track 45 deg, diverging track hor
5926  ((SpeedTag1 == 43) && (SpeedTag2 == 40)) || ((SpeedTag1 == 41) && (SpeedTag2 == 42)) || ((SpeedTag1 == 42) && (SpeedTag2 == 41)))
5927  {
5928  Utilities->CallLogPop(517);
5929  return(true);
5930  }
5931  else
5932  {
5933  Utilities->CallLogPop(518);
5934  return(false);
5935  }
5936 }
5937 
5938 // ---------------------------------------------------------------------------
5939 
5940 /*
5941  bool TMapComp::operator() (const THVPair& lower, const THVPair& higher) const///HLoc VLoc
5942  {
5943  if(lower.second < higher.second) return true;
5944  else if(lower.second > higher.second) return false;
5945  else if(lower.second == higher.second)
5946  {
5947  if(lower.first < higher.first) return true;
5948  }
5949  return false;
5950  }
5951 */
5952 // ---------------------------------------------------------------------------
5953 
5954 void TTrack::PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
5955 // no need to check corresponding gap, if that not set correctly it will be picked up in GapsUnset()
5956 {
5957  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotGap," + TrackElement.LogTrack(1));
5958  if(TrackElement.TrackType != GapJump)
5959  {
5960  throw Exception("Error, Wrong track type in PlotGap");
5961  }
5962  if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] > -1))
5963  {
5964  Disp->PlotOutput(39, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88set);
5965  }
5966  else if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] == -1))
5967  {
5968  Disp->PlotOutput(40, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88unset);
5969  }
5970  if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] > -1))
5971  {
5972  Disp->PlotOutput(41, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89set);
5973  }
5974  else if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] == -1))
5975  {
5976  Disp->PlotOutput(42, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89unset);
5977  }
5978  if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] > -1))
5979  {
5980  Disp->PlotOutput(43, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90set);
5981  }
5982  else if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] == -1))
5983  {
5984  Disp->PlotOutput(44, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90unset);
5985  }
5986  if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] > -1))
5987  {
5988  Disp->PlotOutput(45, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91set);
5989  }
5990  else if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] == -1))
5991  {
5992  Disp->PlotOutput(46, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91unset);
5993  }
5994  if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] > -1))
5995  {
5996  Disp->PlotOutput(47, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92set);
5997  }
5998  else if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] == -1))
5999  {
6000  Disp->PlotOutput(48, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92unset);
6001  }
6002  if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] > -1))
6003  {
6004  Disp->PlotOutput(49, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93set);
6005  }
6006  else if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] == -1))
6007  {
6008  Disp->PlotOutput(50, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93unset);
6009  }
6010  if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] > -1))
6011  {
6012  Disp->PlotOutput(51, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94set);
6013  }
6014  else if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] == -1))
6015  {
6016  Disp->PlotOutput(52, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94unset);
6017  }
6018  if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] > -1))
6019  {
6020  Disp->PlotOutput(53, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95set);
6021  }
6022  else if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] == -1))
6023  {
6024  Disp->PlotOutput(54, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95unset);
6025  }
6026  Utilities->CallLogPop(1101);
6027 }
6028 
6029 // ---------------------------------------------------------------------------
6030 
6031 void TTrack::PlotContinuation(int Caller, TTrackElement TrackElement, TDisplay *Disp) //added for multiplayer to add overlays where coupled
6032 {
6033  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotContinuation," + TrackElement.LogTrack(1));
6034  TrackElement.PlotVariableTrackElement(7, Disp);
6035  if(!MultiplayerOverlayMap.empty()) //if it is empty then no overlays needed [map of key = THVPair, value = graphic pointer]
6036  {
6037  THVPair PosPair;
6038  PosPair.first = TrackElement.HLoc;
6039  PosPair.second = TrackElement.VLoc;
6040  TMultiplayerOverlayMap::iterator MOMIt = MultiplayerOverlayMap.find(PosPair);
6041  if(MOMIt != MultiplayerOverlayMap.end()) //if it is then no overlay is needed
6042  {
6043  Disp->PlotOutput(283, TrackElement.HLoc * 16, TrackElement.VLoc * 16, MOMIt->second);
6044  }
6045  }
6046  Utilities->CallLogPop(2403);
6047 }
6048 
6049 // ---------------------------------------------------------------------------
6050 
6051 void TTrack::PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
6052 {
6053  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPoints," + TrackElement.LogTrack(2));
6054  if(TrackElement.TrackType != Points)
6055  {
6056  throw Exception("Error, Wrong track type in PlotPoints");
6057  }
6058  Disp->PlotPointBlank(0, TrackElement.HLoc, TrackElement.VLoc); // to get rid of earlier fillet
6059  TrackElement.PlotVariableTrackElement(4, Disp);
6060  if(BothFillets)
6061  {
6062  if(TrackElement.SpeedTag < 28)
6063  {
6064  Disp->PlotOutput(55, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][0]);
6065  Disp->PlotOutput(73, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][1]);
6066  }
6067  else if(TrackElement.SpeedTag < 132)
6068  {
6069  Disp->PlotOutput(56, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][0]);
6070  Disp->PlotOutput(74, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][1]);
6071  }
6072  else
6073  {
6074  Disp->PlotOutput(70, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][0]);
6075  Disp->PlotOutput(71, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][1]);
6076  }
6077  }
6078  else if(!TrackElement.Failed) //not failed
6079  {
6080  if(TrackElement.SpeedTag < 28)
6081  {
6082  Disp->PlotOutput(75, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6083  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]); //0 to 7 incl after subtraction
6084  }
6085  else if(TrackElement.SpeedTag < 132)
6086  {
6087  Disp->PlotOutput(76, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6088  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]); //8 to 23 incl after subtraction
6089  }
6090  else
6091  {
6092  Disp->PlotOutput(72, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6093  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]); //24 to 31 incl after subtraction
6094  }
6095  }
6096  else //failed in fixed position
6097  {
6098  if(TrackElement.SpeedTag < 28)
6099  {
6100  Disp->PlotOutput(284, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6101  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]); //0 to 7 incl after subtraction
6102  }
6103  else if(TrackElement.SpeedTag < 132)
6104  {
6105  Disp->PlotOutput(285, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6106  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]); //8 to 23 incl after subtraction
6107  }
6108  else
6109  {
6110  Disp->PlotOutput(286, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6111  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]); //24 to 31 incl after subtraction
6112  }
6113  Disp->GetImage()->Canvas->Draw((TrackElement.HLoc - Display->DisplayOffsetH) * 16, (TrackElement.VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
6114  }
6115 // replot platform if required
6116  TIMPair IMPair;
6117  bool FoundFlag;
6118 
6119  IMPair = GetVectorPositionsFromInactiveTrackMap(15, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
6120  if(FoundFlag)
6121  {
6122  // only one platform possible at points so only need to plot IMPair.first
6123  TTrackElement PlatElement = InactiveTrackElementAt(89, IMPair.first);
6124  PlatElement.PlotVariableTrackElement(5, Disp); // to plot as striped or non-striped depending on whether named or not
6125  }
6126  Utilities->CallLogPop(519);
6127 }
6128 
6129 // ---------------------------------------------------------------------------
6130 
6131 void TTrack::PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
6132 {
6133 // Can't use TrackElement.PlotVariableTrackElement() here as graphic changes depending on signal colour
6134  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignal," + TrackElement.LogTrack(3));
6135  if(TrackElement.TrackType != SignalPost)
6136  {
6137  throw Exception("Error, Wrong track type in PlotSignal");
6138  }
6139  if(!TrackElement.Failed) //added at v2.13.0
6140  {
6141  for(int x = 0; x < 40; x++)
6142  {
6143  if((SigTable[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == TrackElement.Attribute))
6144  {
6145  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6146  Disp->PlotSignalBlank(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6147  // in case existing signal is a double yellow
6148  // plot platforms if present
6149  // Graphics::TBitmap* SignalPlatformGraphic;
6150  // if(PlatformOnSignalSide(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, SignalPlatformGraphic))
6151  // Above dropped at v2.3.0. Now plot either or both platforms if present regardless of which side they are on. The platforms will
6152  // be consistent with the signal graphic as can't enter an inappropriate platform. The new right hand signal option caused platforms
6153  // to not be plotted with the above function.
6154  PlotSignalPlatforms(0, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6155  // now plot signal (double yellow overwrites most of signal platform if present)
6156  // additions at version 0.6 for other aspects & ground sigs
6157  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
6158  {
6159  Disp->PlotOutput(117, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableThreeAspect[x].SigPtr);
6160  }
6161  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
6162  {
6163  Disp->PlotOutput(118, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableTwoAspect[x].SigPtr);
6164  }
6165  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
6166  {
6167  Disp->PlotOutput(119, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
6168  }
6169  else // 4 aspect
6170  {
6171  Disp->PlotOutput(58, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTable[x].SigPtr);
6172  }
6173  if((TrackElement.CallingOnSet) && (TrackElement.SigAspect != TTrackElement::GroundSignal))
6174  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
6175  {
6176  if(TrackElement.SpeedTag == 68)
6177  {
6178  Disp->PlotOutput(59, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm68CallingOn);
6179  }
6180  if(TrackElement.SpeedTag == 69)
6181  {
6182  Disp->PlotOutput(60, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm69CallingOn);
6183  }
6184  if(TrackElement.SpeedTag == 70)
6185  {
6186  Disp->PlotOutput(61, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm70CallingOn);
6187  }
6188  if(TrackElement.SpeedTag == 71)
6189  {
6190  Disp->PlotOutput(62, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm71CallingOn);
6191  }
6192  if(TrackElement.SpeedTag == 72)
6193  {
6194  Disp->PlotOutput(63, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm72CallingOn);
6195  }
6196  if(TrackElement.SpeedTag == 73)
6197  {
6198  Disp->PlotOutput(64, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm73CallingOn);
6199  }
6200  if(TrackElement.SpeedTag == 74)
6201  {
6202  Disp->PlotOutput(65, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm74CallingOn);
6203  }
6204  if(TrackElement.SpeedTag == 75)
6205  {
6206  Disp->PlotOutput(66, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm75CallingOn);
6207  }
6208  }
6209  else if((TrackElement.CallingOnSet) && (TrackElement.SigAspect == TTrackElement::GroundSignal))
6210  // ground signal calling on, need to use normal proceed aspect
6211  {
6212  for(int x = 0; x < 40; x++)
6213  {
6214  if((SigTableGroundSignal[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
6215  {
6216  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6217  Disp->PlotSignalBlank(1, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6218  // plot special signal platform if present
6219  Graphics::TBitmap* SignalPlatformGraphic;
6220  PlotSignalPlatforms(1, TrackElement.HLoc, TrackElement.VLoc, Disp);
6221  // now plot signal
6222  Disp->PlotOutput(123, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
6223  }
6224  }
6225  }
6226  break;
6227  }
6228  }
6229  }
6230  else //failed added at v2.13.0
6231  {
6232  for(int x = 0; x < 8; x++)
6233  {
6234  if(FailedSigTable[x].SpeedTag == TrackElement.SpeedTag)
6235  {
6236  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6237  Disp->PlotSignalBlank(2, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6238  PlotSignalPlatforms(2, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6239  Disp->PlotOutput(287, TrackElement.HLoc * 16, TrackElement.VLoc * 16, FailedSigTable[x].SigPtr);
6240  Disp->GetImage()->Canvas->Draw((TrackElement.HLoc - Display->DisplayOffsetH) * 16, (TrackElement.VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
6241  break;
6242  }
6243  }
6244  }
6245  Utilities->CallLogPop(520);
6246 }
6247 
6248 // ---------------------------------------------------------------------------
6249 
6250 void TTrack::PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
6251 {
6252  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignalPlatforms," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6253  bool FoundFlag;
6254  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(13, HLoc, VLoc, FoundFlag);
6255 
6256  if(!FoundFlag)
6257  {
6258  Utilities->CallLogPop(2112);
6259  return;
6260  }
6261  TTrackElement IAElement1 = InactiveTrackElementAt(124, IMPair.first);
6262  TTrackElement IAElement2 = InactiveTrackElementAt(125, IMPair.second);
6263 
6264  // don't want 'else if' for the below as may need to plot 2 platforms
6265  if((IAElement1.SpeedTag == 76) || (IAElement2.SpeedTag == 76)) // top plat
6266  {
6267  if(IAElement1.LocationName == "") // '2' will be same
6268  {
6269  Disp->PlotOutput(239, HLoc * 16, VLoc * 16, RailGraphics->gl76Striped);
6270  }
6271  else
6272  {
6273  Disp->PlotOutput(240, HLoc * 16, VLoc * 16, RailGraphics->gl76);
6274  }
6275  }
6276  if((IAElement1.SpeedTag == 77) || (IAElement2.SpeedTag == 77)) // bot plat
6277  {
6278  if(IAElement1.LocationName == "") // '2' will be same
6279  {
6280  Disp->PlotOutput(241, HLoc * 16, VLoc * 16, RailGraphics->bm77Striped);
6281  }
6282  else
6283  {
6284  Disp->PlotOutput(242, HLoc * 16, VLoc * 16, RailGraphics->bm77);
6285  }
6286  }
6287  if((IAElement1.SpeedTag == 78) || (IAElement2.SpeedTag == 78)) // lh plat
6288  {
6289  if(IAElement1.LocationName == "") // '2' will be same
6290  {
6291  Disp->PlotOutput(243, HLoc * 16, VLoc * 16, RailGraphics->bm78Striped);
6292  }
6293  else
6294  {
6295  Disp->PlotOutput(244, HLoc * 16, VLoc * 16, RailGraphics->bm78);
6296  }
6297  }
6298  if((IAElement1.SpeedTag == 79) || (IAElement2.SpeedTag == 79)) // rh plat
6299  {
6300  if(IAElement1.LocationName == "") // '2' will be same
6301  {
6302  Disp->PlotOutput(245, HLoc * 16, VLoc * 16, RailGraphics->gl79Striped);
6303  }
6304  else
6305  {
6306  Disp->PlotOutput(246, HLoc * 16, VLoc * 16, RailGraphics->gl79);
6307  }
6308  }
6309  Utilities->CallLogPop(2113);
6310 }
6311 
6312 // ---------------------------------------------------------------------------
6313 
6314 void TTrack::SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
6315 {
6316 // Set attrs to 0=closed to trains; 1=open to trains; 2 = changing = closed to trains
6317  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LowerLinkedLevelCrossingBarrierAttributes," + AnsiString(HLoc) + "," +
6318  AnsiString(VLoc));
6319 // find topmost LC, opening them all (to trains) in turn
6320  int UpStep = 0;
6321 
6322  while(IsLCAtHV(0, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6323  {
6324  SetLCAttributeAtHV(0, HLoc, (VLoc + UpStep), Attr);
6325  UpStep--;
6326  }
6327 // now find bottommost LC, opening them all (to trains) in turn
6328  int DownStep = 1;
6329 
6330  while(IsLCAtHV(1, HLoc, (VLoc + DownStep)))
6331  {
6332  SetLCAttributeAtHV(1, HLoc, (VLoc + DownStep), Attr);
6333  DownStep++;
6334  }
6335 // find leftmost LC, opening them all (to trains) in turn
6336  int LeftStep = 0;
6337 
6338  while(IsLCAtHV(2, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
6339  {
6340  SetLCAttributeAtHV(2, (HLoc + LeftStep), VLoc, Attr);
6341  LeftStep--;
6342  }
6343 // now find rightmost LC, opening them all (to trains) in turn
6344  int RightStep = 1;
6345 
6346  while(IsLCAtHV(3, (HLoc + RightStep), VLoc))
6347  {
6348  SetLCAttributeAtHV(3, (HLoc + RightStep), VLoc, Attr);
6349  RightStep++;
6350  }
6351  Utilities->CallLogPop(1915);
6352 }
6353 
6354 // ---------------------------------------------------------------------------
6355 
6356 void TTrack::SetLinkedManualLCs(int Caller, int HLoc, int VLoc) //sets TypeOfRoute to 2 for all linked LCs
6357 {
6358  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLinkedManualLCs," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6359 // work upwards setting all to manual
6360  int UpStep = -1;
6361 
6362  while(IsLCAtHV(51, HLoc, (VLoc + UpStep)))
6363  {
6364  SetBarriersDownLCToManual(0, HLoc, (VLoc + UpStep));
6365  UpStep--;
6366  }
6367 // work downwards setting all to manual
6368  int DownStep = 1;
6369 
6370  while(IsLCAtHV(52, HLoc, (VLoc + DownStep)))
6371  {
6372  SetBarriersDownLCToManual(1, HLoc, (VLoc + DownStep));
6373  DownStep++;
6374  }
6375 // work leftwards setting all to manual
6376  int LeftStep = -1;
6377 
6378  while(IsLCAtHV(53, (HLoc + LeftStep), VLoc))
6379  {
6380  SetBarriersDownLCToManual(2, (HLoc + LeftStep), VLoc);
6381  LeftStep--;
6382  }
6383 // work rightwards setting all to manual
6384  int RightStep = 1;
6385 
6386  while(IsLCAtHV(54, (HLoc + RightStep), VLoc))
6387  {
6388  SetBarriersDownLCToManual(3, (HLoc + RightStep), VLoc);
6389  RightStep++;
6390  }
6391  Utilities->CallLogPop(2242);
6392 }
6393 
6394 // ---------------------------------------------------------------------------
6395 
6396 void TTrack::SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
6397 {
6398  // Set TypeOfRoute value to 2 to indicate barriers manually closed
6399  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetBarriersDownLCToManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6400  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6401  {
6402  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc))
6403  {
6404  BarriersDownVector.at(x).TypeOfRoute = 2;
6405  break;
6406  }
6407  }
6408  Utilities->CallLogPop(2243);
6409 }
6410 
6411 // ---------------------------------------------------------------------------
6412 
6413 bool TTrack::AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6414 {
6415  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedBarrierDownVectorManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6416 // work upwards
6417  int UpStep = 0; //start with this location
6418 
6419  while(IsLCAtHV(55, HLoc, (VLoc + UpStep)))
6420  {
6421  if(IsBarrierDownVectorAtHVManual(0, HLoc, (VLoc + UpStep), BDVectorPos))
6422  {
6423  Utilities->CallLogPop(2244);
6424  return(true);
6425  }
6426  UpStep--;
6427  }
6428 // work downwards
6429  int DownStep = 1;
6430 
6431  while(IsLCAtHV(56, HLoc, (VLoc + DownStep)))
6432  {
6433  if(IsBarrierDownVectorAtHVManual(1, HLoc, (VLoc + DownStep), BDVectorPos))
6434  {
6435  Utilities->CallLogPop(2245);
6436  return(true);
6437  }
6438  DownStep++;
6439  }
6440 // work leftwards
6441  int LeftStep = -1;
6442 
6443  while(IsLCAtHV(57, (HLoc + LeftStep), VLoc))
6444  {
6445  if(IsBarrierDownVectorAtHVManual(2, (HLoc + LeftStep), VLoc, BDVectorPos))
6446  {
6447  Utilities->CallLogPop(2246);
6448  return(true);
6449  }
6450  LeftStep--;
6451  }
6452 // work rightwards
6453  int RightStep = 1;
6454 
6455  while(IsLCAtHV(58, (HLoc + RightStep), VLoc))
6456  {
6457  if(IsBarrierDownVectorAtHVManual(3, (HLoc + RightStep), VLoc, BDVectorPos))
6458  {
6459  Utilities->CallLogPop(2247);
6460  return(true);
6461  }
6462  RightStep++;
6463  }
6464  Utilities->CallLogPop(2248);
6465  return(false);
6466 }
6467 
6468 // ---------------------------------------------------------------------------
6469 
6470 bool TTrack::IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6471 {
6472  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierDownVectorAtHVManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6473  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6474  {
6475  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc) && (BarriersDownVector.at(x).TypeOfRoute == 2))
6476  {
6477  BDVectorPos = x;
6478  Utilities->CallLogPop(2249);
6479  return(true);
6480  }
6481  }
6482  BDVectorPos = -1;
6483  Utilities->CallLogPop(2250);
6484  return(false);
6485 }
6486 
6487 // ---------------------------------------------------------------------------
6488 
6489 void TTrack::PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
6490 // open to trains
6491 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6492 {
6493  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotLoweredLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
6494  AnsiString(VLoc));
6495  if(!IsLCAtHV(4, HLoc, VLoc))
6496  {
6497  throw Exception("Error, Wrong track type in PlotAndLowerLevelCrossingBarriers");
6498  }
6499  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6500  {
6501  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndLowerLevelCrossingBarriers");
6502  }
6503 // check for adjacent LCs & if so open (to trains)
6504  if(BaseElementSpeedTag == 1) // hor track element
6505  {
6506  // find topmost LC, opening them all (to trains) in turn
6507  int UpStep = 0;
6508  while(IsLCAtHV(5, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6509  {
6510  UpStep--;
6511  }
6512  UpStep++;
6513  // now find bottommost LC, opening them all (to trains) in turn
6514  int DownStep = 1;
6515  while(IsLCAtHV(6, HLoc, (VLoc + DownStep)))
6516  {
6517  DownStep++;
6518  }
6519  DownStep--;
6520  // now plot graphics, UpStep is smallest & DownStep largest
6521  // RouteGraphic is the coloured track element, BaseGraphic is non-coloured
6522  // Only need to plot the coloured graphic for the HLoc & VLoc in the vector as that is the route that is causeing the LC to flash
6523  Graphics::TBitmap *RouteGraphic;
6524  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
6525  if(TypeOfRoute == 1)
6526  {
6527  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
6528  }
6529  else if(TypeOfRoute == 0)
6530  {
6531  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
6532  }
6533  else //manual - no route
6534  {
6535  RouteGraphic = BaseGraphic;
6536  }
6537 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6538 // LinkSigRouteGraphicsPtr[1] ver }
6539 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6540 // LinkNonSigRouteGraphicsPtr[1] ver }
6541 
6542  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6543  {
6544  Disp->PlotOutput(132, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6545  Disp->PlotOutput(133, HLoc * 16, VLoc * 16, RouteGraphic);
6546  if(!Manual)
6547  {
6548  Disp->PlotOutput(134, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
6549  }
6550  else
6551  {
6552  Disp->PlotOutput(247, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
6553  }
6554  }
6555  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
6556  {
6557  if(UpStep == 0)
6558  {
6559  Disp->PlotOutput(135, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6560  Disp->PlotOutput(136, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6561  if(!Manual)
6562  {
6563  Disp->PlotOutput(137, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6564  }
6565  else
6566  {
6567  Disp->PlotOutput(248, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6568  }
6569  Disp->PlotOutput(138, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6570  Disp->PlotOutput(139, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6571  if(!Manual)
6572  {
6573  Disp->PlotOutput(140, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6574  }
6575  else
6576  {
6577  Disp->PlotOutput(249, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6578  }
6579  }
6580  else
6581  {
6582  Disp->PlotOutput(195, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6583  Disp->PlotOutput(196, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6584  if(!Manual)
6585  {
6586  Disp->PlotOutput(197, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6587  }
6588  else
6589  {
6590  Disp->PlotOutput(250, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6591  }
6592  Disp->PlotOutput(198, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6593  Disp->PlotOutput(199, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6594  if(!Manual)
6595  {
6596  Disp->PlotOutput(200, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6597  }
6598  else
6599  {
6600  Disp->PlotOutput(251, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6601  }
6602  }
6603  }
6604  else // at least one plain graphic
6605  {
6606  if(UpStep == 0)
6607  {
6608  Disp->PlotOutput(141, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6609  Disp->PlotOutput(142, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6610  if(!Manual)
6611  {
6612  Disp->PlotOutput(143, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6613  }
6614  else
6615  {
6616  Disp->PlotOutput(252, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6617  }
6618  Disp->PlotOutput(144, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6619  Disp->PlotOutput(145, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6620  if(!Manual)
6621  {
6622  Disp->PlotOutput(146, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6623  }
6624  else
6625  {
6626  Disp->PlotOutput(253, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6627  }
6628  }
6629  else if(DownStep == 0)
6630  {
6631  Disp->PlotOutput(201, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6632  Disp->PlotOutput(202, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6633  if(!Manual)
6634  {
6635  Disp->PlotOutput(203, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6636  }
6637  else
6638  {
6639  Disp->PlotOutput(254, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6640  }
6641  Disp->PlotOutput(204, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6642  Disp->PlotOutput(205, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6643  if(!Manual)
6644  {
6645  Disp->PlotOutput(206, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6646  }
6647  else
6648  {
6649  Disp->PlotOutput(255, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6650  }
6651  }
6652  else
6653  {
6654  Disp->PlotOutput(207, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6655  Disp->PlotOutput(208, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6656  if(!Manual)
6657  {
6658  Disp->PlotOutput(209, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6659  }
6660  else
6661  {
6662  Disp->PlotOutput(256, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6663  }
6664  Disp->PlotOutput(210, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6665  Disp->PlotOutput(211, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6666  if(!Manual)
6667  {
6668  Disp->PlotOutput(212, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6669  }
6670  else
6671  {
6672  Disp->PlotOutput(257, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6673  }
6674  }
6675  for(int x = (UpStep + 1); x < DownStep; x++)
6676  {
6677  Disp->PlotOutput(147, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
6678  if(x == 0)
6679  {
6680  Disp->PlotOutput(148, HLoc * 16, (VLoc + x) * 16, RouteGraphic);
6681  }
6682  else
6683  {
6684  Disp->PlotOutput(213, HLoc * 16, (VLoc + x) * 16, BaseGraphic);
6685  }
6686  if(!Manual)
6687  {
6688  Disp->PlotOutput(149, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
6689  }
6690  else
6691  {
6692  Disp->PlotOutput(258, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
6693  }
6694  }
6695  }
6696  Disp->Update();
6697  Utilities->CallLogPop(1958);
6698  return;
6699  }
6700 
6701  else // ver track element
6702  {
6703  // find leftmost LC, opening them all (to trains) in turn
6704  int LStep = 0;
6705  while(IsLCAtHV(7, (HLoc + LStep), VLoc))
6706  {
6707  LStep--;
6708  }
6709  LStep++;
6710  // now find rightmost LC, opening them all (to trains) in turn
6711  int RStep = 1;
6712  while(IsLCAtHV(8, (HLoc + RStep), VLoc))
6713  {
6714  RStep++;
6715  }
6716  RStep--;
6717  // now plot graphics, LStep is smallest & RStep largest
6718  Graphics::TBitmap *RouteGraphic;
6719  Graphics::TBitmap *BaseGraphic = RailGraphics->gl2;
6720  if(TypeOfRoute == 1)
6721  {
6722  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
6723  }
6724  else if(TypeOfRoute == 0)
6725  {
6726  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
6727  }
6728  else //manual
6729  {
6730  RouteGraphic = BaseGraphic;
6731  }
6732 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6733 // LinkSigRouteGraphicsPtr[1] ver }
6734 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6735 // LinkNonSigRouteGraphicsPtr[1] ver }
6736  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6737  {
6738  Disp->PlotOutput(150, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6739  Disp->PlotOutput(151, HLoc * 16, VLoc * 16, RouteGraphic);
6740  if(!Manual)
6741  {
6742  Disp->PlotOutput(152, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
6743  }
6744  else
6745  {
6746  Disp->PlotOutput(259, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
6747  }
6748  }
6749  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
6750  {
6751  if(LStep == 0)
6752  {
6753  Disp->PlotOutput(153, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6754  Disp->PlotOutput(154, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6755  if(!Manual)
6756  {
6757  Disp->PlotOutput(155, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6758  }
6759  else
6760  {
6761  Disp->PlotOutput(260, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6762  }
6763  Disp->PlotOutput(156, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6764  Disp->PlotOutput(157, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6765  if(!Manual)
6766  {
6767  Disp->PlotOutput(158, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6768  }
6769  else
6770  {
6771  Disp->PlotOutput(261, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6772  }
6773  }
6774  else
6775  {
6776  Disp->PlotOutput(214, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6777  Disp->PlotOutput(215, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6778  if(!Manual)
6779  {
6780  Disp->PlotOutput(216, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6781  }
6782  else
6783  {
6784  Disp->PlotOutput(262, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6785  }
6786  Disp->PlotOutput(217, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6787  Disp->PlotOutput(218, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6788  if(!Manual)
6789  {
6790  Disp->PlotOutput(219, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6791  }
6792  else
6793  {
6794  Disp->PlotOutput(263, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6795  }
6796  }
6797  }
6798  else // at least one plain graphic
6799  {
6800  if(LStep == 0)
6801  {
6802  Disp->PlotOutput(159, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6803  Disp->PlotOutput(160, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6804  if(!Manual)
6805  {
6806  Disp->PlotOutput(161, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6807  }
6808  else
6809  {
6810  Disp->PlotOutput(264, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6811  }
6812  Disp->PlotOutput(162, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6813  Disp->PlotOutput(163, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6814  if(!Manual)
6815  {
6816  Disp->PlotOutput(164, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6817  }
6818  else
6819  {
6820  Disp->PlotOutput(265, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6821  }
6822  }
6823  else if(RStep == 0)
6824  {
6825  Disp->PlotOutput(220, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6826  Disp->PlotOutput(221, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6827  if(!Manual)
6828  {
6829  Disp->PlotOutput(222, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6830  }
6831  else
6832  {
6833  Disp->PlotOutput(266, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6834  }
6835  Disp->PlotOutput(223, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6836  Disp->PlotOutput(224, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6837  if(!Manual)
6838  {
6839  Disp->PlotOutput(225, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6840  }
6841  else
6842  {
6843  Disp->PlotOutput(267, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6844  }
6845  }
6846  else
6847  {
6848  Disp->PlotOutput(226, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6849  Disp->PlotOutput(227, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6850  if(!Manual)
6851  {
6852  Disp->PlotOutput(228, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6853  }
6854  else
6855  {
6856  Disp->PlotOutput(268, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6857  }
6858  Disp->PlotOutput(229, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6859  Disp->PlotOutput(230, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6860  if(!Manual)
6861  {
6862  Disp->PlotOutput(231, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6863  }
6864  else
6865  {
6866  Disp->PlotOutput(269, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6867  }
6868  }
6869  for(int x = (LStep + 1); x < RStep; x++)
6870  {
6871  Disp->PlotOutput(165, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6872  if(x == 0)
6873  {
6874  Disp->PlotOutput(166, (HLoc + x) * 16, VLoc * 16, RouteGraphic);
6875  }
6876  else
6877  {
6878  Disp->PlotOutput(232, (HLoc + x) * 16, VLoc * 16, BaseGraphic);
6879  }
6880  if(!Manual)
6881  {
6882  Disp->PlotOutput(167, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
6883  }
6884  else
6885  {
6886  Disp->PlotOutput(270, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
6887  }
6888  }
6889  }
6890  Disp->Update();
6891  Utilities->CallLogPop(1896);
6892  return;
6893  }
6894 }
6895 
6896 // ---------------------------------------------------------------------------
6897 
6898 void TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual) // open to trains
6899 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6900 {
6901  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers," +
6902  AnsiString(HLoc) + "," + AnsiString(VLoc));
6903  if(!IsLCAtHV(29, HLoc, VLoc))
6904  {
6905  throw Exception("Error, Wrong track type in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
6906  }
6907  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6908  {
6909  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
6910  }
6911 // check for adjacent LCs & if so open (to trains)
6912  if(BaseElementSpeedTag == 1) // hor track element
6913  {
6914  // find topmost LC, opening them all (to trains) in turn
6915  int UpStep = 0;
6916  while(IsLCAtHV(30, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6917  {
6918  UpStep--;
6919  }
6920  UpStep++;
6921  // now find bottommost LC, opening them all (to trains) in turn
6922  int DownStep = 1;
6923  while(IsLCAtHV(31, HLoc, (VLoc + DownStep)))
6924  {
6925  DownStep++;
6926  }
6927  DownStep--;
6928  // now plot graphics, UpStep is smallest & DownStep largest
6929  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6930  {
6931  if(!Manual)
6932  {
6933  Disp->PlotOutput(179, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
6934  }
6935  else
6936  {
6937  Disp->PlotOutput(271, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
6938  }
6939  }
6940  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
6941  {
6942  if(!Manual)
6943  {
6944  Disp->PlotOutput(180, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6945  Disp->PlotOutput(181, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6946  }
6947  else
6948  {
6949  Disp->PlotOutput(272, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6950  Disp->PlotOutput(273, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6951  }
6952  }
6953  else // at least one plain graphic
6954  {
6955  if(!Manual)
6956  {
6957  Disp->PlotOutput(182, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6958  Disp->PlotOutput(183, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6959  for(int x = (UpStep + 1); x < DownStep; x++)
6960  {
6961  Disp->PlotOutput(184, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
6962  }
6963  }
6964  else
6965  {
6966  Disp->PlotOutput(274, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6967  Disp->PlotOutput(275, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6968  for(int x = (UpStep + 1); x < DownStep; x++)
6969  {
6970  Disp->PlotOutput(276, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
6971  }
6972  }
6973  }
6974  // set markers
6975  for(int x = UpStep; x <= DownStep; x++)
6976  {
6977  GetInactiveTrackElementFromTrackMap(3, HLoc, (VLoc + x)).LCPlotted = true; // plotted
6978  }
6979  Display->Update();
6980  Utilities->CallLogPop(1944);
6981  return;
6982  }
6983 
6984  else // ver track element
6985  {
6986  // find leftmost LC, opening them all (to trains) in turn
6987  int LStep = 0;
6988  while(IsLCAtHV(32, (HLoc + LStep), VLoc))
6989  {
6990  LStep--;
6991  }
6992  LStep++;
6993  // now find rightmost LC, opening them all (to trains) in turn
6994  int RStep = 1;
6995  while(IsLCAtHV(33, (HLoc + RStep), VLoc))
6996  {
6997  RStep++;
6998  }
6999  RStep--;
7000  // now plot graphics, LStep is smallest & RStep largest
7001  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
7002  {
7003  if(!Manual)
7004  {
7005  Disp->PlotOutput(185, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
7006  }
7007  else
7008  {
7009  Disp->PlotOutput(277, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
7010  }
7011  }
7012  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
7013  {
7014  if(!Manual)
7015  {
7016  Disp->PlotOutput(186, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7017  Disp->PlotOutput(187, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7018  }
7019  else
7020  {
7021  Disp->PlotOutput(278, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7022  Disp->PlotOutput(279, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7023  }
7024  }
7025  else // at least one plain graphic
7026  {
7027  if(!Manual)
7028  {
7029  Disp->PlotOutput(188, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7030  Disp->PlotOutput(189, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7031  for(int x = (LStep + 1); x < RStep; x++)
7032  {
7033  Disp->PlotOutput(190, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
7034  }
7035  }
7036  else
7037  {
7038  Disp->PlotOutput(280, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7039  Disp->PlotOutput(281, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7040  for(int x = (LStep + 1); x < RStep; x++)
7041  {
7042  Disp->PlotOutput(282, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
7043  }
7044  }
7045  }
7046  // set markers
7047  for(int x = LStep; x <= RStep; x++)
7048  {
7049  GetInactiveTrackElementFromTrackMap(4, (HLoc + x), VLoc).LCPlotted = true; // plotted
7050  }
7051  Disp->Update();
7052  Utilities->CallLogPop(1945);
7053  return;
7054  }
7055 }
7056 
7057 // ---------------------------------------------------------------------------
7058 
7059 void TTrack::PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp) // closed to trains
7060 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7061 {
7062  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotRaisedLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
7063  AnsiString(VLoc));
7064  if(!IsLCAtHV(9, HLoc, VLoc))
7065  {
7066  throw Exception("Error, Wrong track type in PlotAndRaiseLevelCrossingBarriers");
7067  }
7068  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7069  {
7070  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndRaiseLevelCrossingBarriers");
7071  }
7072 // check for adjacent LCs & if so close (to trains)
7073  if(BaseElementSpeedTag == 1) // hor track element
7074  {
7075  // find topmost LC, closing them all (to trains) in turn
7076  int UpStep = 0;
7077  while(IsLCAtHV(10, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7078  {
7079  UpStep--;
7080  }
7081  UpStep++;
7082  // now find bottommost LC, opening them all (to trains) in turn
7083  int DownStep = 1;
7084  while(IsLCAtHV(11, HLoc, (VLoc + DownStep)))
7085  {
7086  DownStep++;
7087  }
7088  DownStep--;
7089  // now plot graphics, UpStep is smallest & DownStep largest
7090  for(int x = UpStep; x < (DownStep + 1); x++)
7091  {
7092  Disp->PlotOutput(168, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
7093  Disp->PlotOutput(169, HLoc * 16, (VLoc + x) * 16, RailGraphics->gl1);
7094  Disp->PlotOutput(170, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
7095  }
7096  Disp->Update();
7097  Utilities->CallLogPop(1959);
7098  return;
7099  }
7100 
7101  else // ver track element
7102  {
7103  // find leftmost LC, closing them all (to trains) in turn
7104  int LStep = 0;
7105  while(IsLCAtHV(12, (HLoc + LStep), VLoc))
7106  {
7107  LStep--;
7108  }
7109  LStep++;
7110  // now find rightmost LC, opening them all (to trains) in turn
7111  int RStep = 1;
7112  while(IsLCAtHV(13, (HLoc + RStep), VLoc))
7113  {
7114  RStep++;
7115  }
7116  RStep--;
7117  // now plot graphics, LStep is smallest & RStep largest
7118  for(int x = LStep; x < (RStep + 1); x++)
7119  {
7120  Disp->PlotOutput(171, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7121  Disp->PlotOutput(172, (HLoc + x) * 16, VLoc * 16, RailGraphics->gl2);
7122  Disp->PlotOutput(173, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
7123  }
7124  Disp->Update();
7125  Utilities->CallLogPop(1960);
7126  return;
7127  }
7128 }
7129 
7130 // ---------------------------------------------------------------------------
7131 
7132 void TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
7133 // closed to trains
7134 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7135 {
7136  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers," +
7137  AnsiString(HLoc) + "," + AnsiString(VLoc));
7138  if(!IsLCAtHV(34, HLoc, VLoc))
7139  {
7140  throw Exception("Error, Wrong track type in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
7141  }
7142  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7143  {
7144  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
7145  }
7146  TTrackElement TE;
7147 
7148 // check for adjacent LCs & if so close (to trains)
7149  if(BaseElementSpeedTag == 1) // hor track element
7150  {
7151  // find topmost LC, closing them all (to trains) in turn
7152  int UpStep = 0;
7153  while(IsLCAtHV(35, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7154  {
7155  UpStep--;
7156  }
7157  UpStep++;
7158  // now find bottommost LC, opening them all (to trains) in turn
7159  int DownStep = 1;
7160  while(IsLCAtHV(36, HLoc, (VLoc + DownStep)))
7161  {
7162  DownStep++;
7163  }
7164  DownStep--;
7165  // now plot graphics, UpStep is smallest & DownStep largest
7166  for(int x = UpStep; x <= DownStep; x++)
7167  {
7168  Disp->PlotOutput(191, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
7169  GetInactiveTrackElementFromTrackMap(1, HLoc, (VLoc + x)).LCPlotted = true; // plotted
7170  }
7171  Display->Update();
7172  Utilities->CallLogPop(1946);
7173  return;
7174  }
7175 
7176  else // ver track element
7177  {
7178  // find leftmost LC, closing them all (to trains) in turn
7179  int LStep = 0;
7180  while(IsLCAtHV(37, (HLoc + LStep), VLoc))
7181  {
7182  LStep--;
7183  }
7184  LStep++;
7185  // now find rightmost LC, opening them all (to trains) in turn
7186  int RStep = 1;
7187  while(IsLCAtHV(38, (HLoc + RStep), VLoc))
7188  {
7189  RStep++;
7190  }
7191  RStep--;
7192  // now plot graphics, LStep is smallest & RStep largest
7193  for(int x = LStep; x <= RStep; x++)
7194  {
7195  Disp->PlotOutput(192, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
7196  GetInactiveTrackElementFromTrackMap(2, (HLoc + x), VLoc).LCPlotted = true; // plotted
7197  }
7198  Display->Update();
7199  Utilities->CallLogPop(1947);
7200  return;
7201  }
7202 }
7203 
7204 // ---------------------------------------------------------------------------
7205 
7206 void TTrack::PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
7207 {
7208  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotBaseElementsOnly," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7209  Graphics::TBitmap *RouteGraphic;
7210  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
7211 
7212  if(BaseElementSpeedTag == 1)
7213  {
7214  if(TypeOfRoute == 1)
7215  {
7216  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
7217  }
7218  else if(TypeOfRoute == 0)
7219  {
7220  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
7221  }
7222  else //manual
7223  {
7224  RouteGraphic = BaseGraphic;
7225  }
7226  if(State == Raising)
7227  {
7228  RouteGraphic = BaseGraphic;
7229  }
7230  }
7231  else
7232  {
7233  BaseGraphic = RailGraphics->gl2;
7234  if(TypeOfRoute == 1)
7235  {
7236  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
7237  }
7238  else if(TypeOfRoute == 0)
7239  {
7240  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
7241  }
7242  else
7243  {
7244  RouteGraphic = BaseGraphic; //manual
7245  }
7246  if(State == Raising)
7247  {
7248  RouteGraphic = BaseGraphic;
7249  }
7250  }
7251  int UpStep = 0;
7252 
7253  while(IsLCAtHV(14, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7254  {
7255  Disp->PlotOutput(174, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
7256  if(UpStep == 0)
7257  {
7258  Disp->PlotOutput(175, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
7259  }
7260  else
7261  {
7262  Disp->PlotOutput(234, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
7263  }
7264  UpStep--;
7265  }
7266 // now find bottommost LC, opening them all (to trains) in turn
7267  int DownStep = 1;
7268 
7269  while(IsLCAtHV(15, HLoc, (VLoc + DownStep)))
7270  {
7271  Disp->PlotOutput(176, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
7272  Disp->PlotOutput(177, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
7273  DownStep++;
7274  }
7275  int LeftStep = 0;
7276 
7277  while(IsLCAtHV(16, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7278  {
7279  Disp->PlotOutput(233, (HLoc + LeftStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7280  if(LeftStep == 0)
7281  {
7282  Disp->PlotOutput(235, (HLoc + LeftStep) * 16, VLoc * 16, RouteGraphic);
7283  }
7284  else
7285  {
7286  Disp->PlotOutput(236, (HLoc + LeftStep) * 16, VLoc * 16, BaseGraphic);
7287  }
7288  LeftStep--;
7289  }
7290 // now find rightmost LC, opening them all (to trains) in turn
7291  int RightStep = 1;
7292 
7293  while(IsLCAtHV(17, (HLoc + RightStep), VLoc))
7294  {
7295  Disp->PlotOutput(237, (HLoc + RightStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7296  Disp->PlotOutput(238, (HLoc + RightStep) * 16, VLoc * 16, BaseGraphic);
7297  RightStep++;
7298  }
7299  Disp->Update();
7300  Utilities->CallLogPop(1914);
7301 }
7302 
7303 // ---------------------------------------------------------------------------
7304 
7305 bool TTrack::IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully down
7306 {
7307 // return false for no LC there, flashing or a closed (to trains) LC
7308  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCBarrierDownAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7309  bool FoundFlag;
7310  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(21, HLoc, VLoc, FoundFlag);
7311 
7312  if(!FoundFlag)
7313  {
7314  Utilities->CallLogPop(1898);
7315  return(false);
7316  }
7317  if(InactiveTrackElementAt(100, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7318  {
7319  Utilities->CallLogPop(1899);
7320  return(false);
7321  }
7322  if(InactiveTrackElementAt(103, IMPair.first).Attribute == 1)
7323  {
7324  Utilities->CallLogPop(1900);
7325  return(true);
7326  }
7327  Utilities->CallLogPop(1901);
7328  return(false);
7329 }
7330 
7331 // ---------------------------------------------------------------------------
7332 
7333 bool TTrack::IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully up
7334 {
7335 // return false for no LC there, flashing LC or open (to trains) LC
7336  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierUpLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7337  bool FoundFlag;
7338  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(24, HLoc, VLoc, FoundFlag);
7339 
7340  if(!FoundFlag)
7341  {
7342  Utilities->CallLogPop(1922);
7343  return(false);
7344  }
7345  if(InactiveTrackElementAt(110, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7346  {
7347  Utilities->CallLogPop(1923);
7348  return(false);
7349  }
7350  if(InactiveTrackElementAt(111, IMPair.first).Attribute == 0)
7351  {
7352  Utilities->CallLogPop(1924);
7353  return(true);
7354  }
7355  Utilities->CallLogPop(1925);
7356  return(false);
7357 }
7358 
7359 // ---------------------------------------------------------------------------
7360 
7361 bool TTrack::IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
7362 {
7363 // return true for barrier in process of moving
7364  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierFlashingAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7365  bool FoundFlag;
7366  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(25, HLoc, VLoc, FoundFlag);
7367 
7368  if(!FoundFlag)
7369  {
7370  Utilities->CallLogPop(1918);
7371  return(false);
7372  }
7373  if(InactiveTrackElementAt(112, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7374  {
7375  Utilities->CallLogPop(1919);
7376  return(false);
7377  }
7378  if(InactiveTrackElementAt(113, IMPair.first).Attribute == 2)
7379  {
7380  Utilities->CallLogPop(1920);
7381  return(true);
7382  }
7383  Utilities->CallLogPop(1921);
7384  return(false);
7385 }
7386 
7387 // ---------------------------------------------------------------------------
7388 
7389 bool TTrack::IsLCAtHV(int Caller, int HLoc, int VLoc)
7390 {
7391 // return true for an LC at H&V
7392  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7393  bool FoundFlag;
7394  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(22, HLoc, VLoc, FoundFlag);
7395 
7396  if(!FoundFlag)
7397  {
7398  Utilities->CallLogPop(1902);
7399  return(false);
7400  }
7401  if(InactiveTrackElementAt(101, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7402  {
7403  Utilities->CallLogPop(1903);
7404  return(false);
7405  }
7406  Utilities->CallLogPop(1904);
7407  return(true);
7408 }
7409 
7410 // ---------------------------------------------------------------------------
7411 
7412 void TTrack::SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
7413 {
7414  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCAttributeAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7415  AnsiString(Attr));
7416  bool FoundFlag;
7417  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(23, HLoc, VLoc, FoundFlag);
7418 
7419  if(!FoundFlag)
7420  {
7421  throw Exception("Element not found in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7422  }
7423  if(InactiveTrackElementAt(102, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7424  {
7425  throw Exception("Element not a level crossing in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7426  }
7427  InactiveTrackElementAt(104, IMPair.first).Attribute = Attr;
7428  Utilities->CallLogPop(1905);
7429  return;
7430 }
7431 
7432 // ---------------------------------------------------------------------------
7433 
7435 {
7436  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetLevelCrossings");
7437  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
7438  {
7439  TTrackElement InactiveTrackElement = InactiveTrackElementAt(140, x);
7440  if(InactiveTrackElement.TrackType == LevelCrossing)
7441  {
7442  InactiveTrackElementAt(141, x).Attribute = 0;
7443  // though this only resets the attributes the LC will display correctly when call Clearand.. in BaseMode
7444  }
7445  }
7446  Utilities->CallLogPop(1913);
7447  return;
7448 }
7449 
7450 // ---------------------------------------------------------------------------
7451 
7452 bool TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
7453 {
7454 // return true if there is either a route set or being set on any element or a train on any element
7455  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedLevelCrossingElementsWithRoutesOrTrains," + AnsiString(HLoc) +
7456  "," + AnsiString(VLoc));
7457 
7458  THVPair TrackMapKeyPair;
7459  TTrack::TTrackMapIterator TrackMapPtr;
7460  int DummyRouteNumber;
7461 
7462  TrainPresent = false;
7463 // find topmost LC, checking each for routes & trains
7464  int UpStep = 0;
7465 
7466  while(IsLCAtHV(25, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7467  {
7468  TrackMapKeyPair.first = HLoc;
7469  TrackMapKeyPair.second = VLoc + UpStep;
7470  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7471  if(AllRoutes->GetRouteTypeAndNumber(20, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7472  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7473  {
7474  Utilities->CallLogPop(1932);
7475  return(true);
7476  }
7477  if(TrackElementAt(867, TrackMapPtr->second).TrainIDOnElement != -1)
7478  {
7479  TrainPresent = true;
7480  Utilities->CallLogPop(1933);
7481  return(true);
7482  }
7483  if(LCInSearchVector(0, HLoc, (VLoc + UpStep), SearchVector)) //route being set, added at v2.8.0
7484  {
7485  Utilities->CallLogPop(2274);
7486  return(true);
7487  }
7488  UpStep--;
7489  }
7490 // now find bottommost LC, opening them all (to trains) in turn
7491  int DownStep = 1;
7492 
7493  while(IsLCAtHV(26, HLoc, (VLoc + DownStep)))
7494  {
7495  TrackMapKeyPair.first = HLoc;
7496  TrackMapKeyPair.second = VLoc + DownStep;
7497  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7498  if(AllRoutes->GetRouteTypeAndNumber(21, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7499  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7500  {
7501  Utilities->CallLogPop(1934);
7502  return(true);
7503  }
7504  if(TrackElementAt(868, TrackMapPtr->second).TrainIDOnElement != -1)
7505  {
7506  TrainPresent = true;
7507  Utilities->CallLogPop(1935);
7508  return(true);
7509  }
7510  if(LCInSearchVector(1, HLoc, (VLoc + DownStep), SearchVector)) //route being set, added at v2.8.0
7511  {
7512  Utilities->CallLogPop(2275);
7513  return(true);
7514  }
7515  DownStep++;
7516  }
7517 // find leftmost LC
7518  int LeftStep = 0;
7519 
7520  while(IsLCAtHV(27, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7521  {
7522  TrackMapKeyPair.first = HLoc + LeftStep;
7523  TrackMapKeyPair.second = VLoc;
7524  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7525  if(AllRoutes->GetRouteTypeAndNumber(22, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7526  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7527  {
7528  Utilities->CallLogPop(1936);
7529  return(true);
7530  }
7531  if(TrackElementAt(869, TrackMapPtr->second).TrainIDOnElement != -1)
7532  {
7533  TrainPresent = true;
7534  Utilities->CallLogPop(1937);
7535  return(true);
7536  }
7537  if(LCInSearchVector(2, (HLoc + LeftStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7538  {
7539  Utilities->CallLogPop(2276);
7540  return(true);
7541  }
7542  LeftStep--;
7543  }
7544 // now find rightmost LC, opening them all (to trains) in turn
7545  int RightStep = 1;
7546 
7547  while(IsLCAtHV(28, (HLoc + RightStep), VLoc))
7548  {
7549  TrackMapKeyPair.first = HLoc + RightStep;
7550  TrackMapKeyPair.second = VLoc;
7551  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7552  if(AllRoutes->GetRouteTypeAndNumber(23, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7553  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7554  {
7555  Utilities->CallLogPop(1938);
7556  return(true);
7557  }
7558  if(TrackElementAt(870, TrackMapPtr->second).TrainIDOnElement != -1)
7559  {
7560  TrainPresent = true;
7561  Utilities->CallLogPop(1939);
7562  return(true);
7563  }
7564  if(LCInSearchVector(3, (HLoc + RightStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7565  {
7566  Utilities->CallLogPop(2277);
7567  return(true);
7568  }
7569  RightStep++;
7570  }
7571  Utilities->CallLogPop(1940);
7572  return(false);
7573 }
7574 
7575 // ---------------------------------------------------------------------------
7576 
7577 bool TTrack::LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector) //added at v2.8.0
7578 {
7579  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LCInSearchVector," + HLoc + "," + VLoc);
7580  for(unsigned int x = 0; x < SearchVector.size(); x++)
7581  {
7582  if((TrackElementAt(1019, SearchVector.at(x).GetTrackVectorPosition()).HLoc == HLoc) && (TrackElementAt(1020, SearchVector.at(x).GetTrackVectorPosition()).VLoc == VLoc))
7583  {
7584  Utilities->CallLogPop(2278);
7585  return(true);
7586  }
7587  }
7588  Utilities->CallLogPop(2279);
7589  return(false);
7590 }
7591 
7592 // ---------------------------------------------------------------------------
7593 
7594 void TTrack::PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
7595 {
7596  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallFlashingLinkedLevelCrossings," +
7597  AnsiString(HLoc) + "," + AnsiString(VLoc));
7598  if(!IsLCAtHV(60, HLoc, VLoc))
7599  {
7600  throw Exception("PlotSmallFlashingLinkedLevelCrossings");
7601  }
7602 
7603 // check for adjacent LCs
7604  // find topmost LC
7605  int UpStep = 0;
7606  while(IsLCAtHV(61, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7607  {
7608  UpStep--;
7609  }
7610  UpStep++;
7611  // now find bottommost LC, opening them all (to trains) in turn
7612  int DownStep = 1;
7613  while(IsLCAtHV(62, HLoc, (VLoc + DownStep)))
7614  {
7615  DownStep++;
7616  }
7617  DownStep--;
7618  // now plot graphics, UpStep is smallest & DownStep largest
7619  for(int x = UpStep; x <= DownStep; x++)
7620  {
7621  Disp->PlotSmallOutput(24, HLoc * 4, (VLoc + x) * 4, GraphicPtr);
7622  }
7623 
7624  // find leftmost LC, closing them all (to trains) in turn
7625  int LStep = 0;
7626  while(IsLCAtHV(63, (HLoc + LStep), VLoc))
7627  {
7628  LStep--;
7629  }
7630  LStep++;
7631  // now find rightmost LC, opening them all (to trains) in turn
7632  int RStep = 1;
7633  while(IsLCAtHV(64, (HLoc + RStep), VLoc))
7634  {
7635  RStep++;
7636  }
7637  RStep--;
7638  // now plot graphics, LStep is smallest & RStep largest
7639  for(int x = LStep; x <= RStep; x++)
7640  {
7641  Disp->PlotSmallOutput(25, (HLoc + x) * 4, VLoc * 4, GraphicPtr);
7642  }
7643  Display->Update();
7644  Utilities->CallLogPop(2315);
7645  return;
7646 }
7647 
7648 // ---------------------------------------------------------------------------
7649 
7650 Graphics::TBitmap *TTrack::GetFilletGraphic(int Caller, TTrackElement TrackElement)
7651 {
7652  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFilletGraphic," + TrackElement.LogTrack(4));
7653  if(TrackElement.TrackType != Points)
7654  {
7655  throw Exception("Error, Wrong track type in GetFilletGraphic");
7656  }
7657  if(TrackElement.SpeedTag < 28)
7658  {
7659  Utilities->CallLogPop(521);
7660  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]);
7661  }
7662  else if(TrackElement.SpeedTag < 132)
7663  {
7664  Utilities->CallLogPop(522);
7665 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7666  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]);
7667  }
7668  else
7669  {
7670  Utilities->CallLogPop(1537);
7671  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]);
7672  }
7673 }
7674 
7675 // ---------------------------------------------------------------------------
7676 
7678 {
7679  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAllTrainIDsAndFailedPointOrigSpeedLimits");
7680  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
7681  {
7682  TrackElementAt(1351, x).TrainIDOnElement = -1;
7685  }
7686  Utilities->CallLogPop(1342);
7687 }
7688 
7689 // ---------------------------------------------------------------------------
7690 
7691 void TTrack::GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
7692 /*
7693  Converts the screen position to the true (without offsets) HLoc, VLoc 16 x 16 square that the screen position lies within
7694 */
7695 {
7696  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackLocsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7697  AnsiString(ScreenPosV));
7698  HLoc = div(ScreenPosH, 16).quot + Display->DisplayOffsetH;
7699  VLoc = div(ScreenPosV, 16).quot + Display->DisplayOffsetV;
7700 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7701  Utilities->CallLogPop(535);
7702 }
7703 
7704 // ---------------------------------------------------------------------------
7705 
7706 void TTrack::GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
7707 /*
7708  Converts the screen position to the true (without offsets) position
7709 */
7710 {
7711  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTruePositionsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7712  AnsiString(ScreenPosV));
7713  HPos = ScreenPosH + (Display->DisplayOffsetH * 16);
7714  VPos = ScreenPosV + (Display->DisplayOffsetV * 16);
7715  Utilities->CallLogPop(536);
7716 }
7717 
7718 // ---------------------------------------------------------------------------
7719 
7720 void TTrack::GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
7721 {
7722  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetScreenPositionsFromTruePos," + AnsiString(HPosTrue) + "," +
7723  AnsiString(VPosTrue));
7724  ScreenPosH = HPosTrue - (Display->DisplayOffsetH * 16);
7725  ScreenPosV = VPosTrue - (Display->DisplayOffsetV * 16);
7726  Utilities->CallLogPop(537);
7727 }
7728 
7729 // ---------------------------------------------------------------------------
7730 
7731 void TTrack::CheckMapAndTrack(int Caller) // test
7732 {
7733  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndTrack");
7734  int Zeroes = 0;
7735  bool FoundFlag;
7736 
7737  for(unsigned int a = 0; a < TrackVector.size(); a++)
7738  {
7739  TTrackElement CheckElement = Track->TrackElementAt(1354, a);
7740  if(CheckElement.SpeedTag == 0)
7741  {
7742  Zeroes++; // zeroed elements not saved in map
7743  }
7744  else
7745  {
7746  int MapVecPos = GetVectorPositionFromTrackMap(16, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7747  if(!FoundFlag)
7748  {
7749  throw Exception("CheckMapAndTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7750  " in TrackMap, Caller=" + (AnsiString)Caller);
7751  }
7752  if(MapVecPos != (int)a)
7753  {
7754  throw Exception("CheckMapAndTrack Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7755  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)MapVecPos + " TrackVectorPos value=" + (AnsiString)a + " Caller=" +
7756  (AnsiString)Caller);
7757  }
7758  }
7759  }
7760  if(TrackVector.size() != (TrackMap.size() + Zeroes))
7761  {
7762  throw Exception("CheckMapAndTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7763  " Caller=" + (AnsiString)Caller);
7764  }
7765  Utilities->CallLogPop(538);
7766  return;
7767 }
7768 
7769 // ---------------------------------------------------------------------------
7770 
7771 void TTrack::CheckMapAndInactiveTrack(int Caller) // test
7772 {
7773  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndInactiveTrack");
7774  bool FoundFlag;
7775  TIMPair InactivePair;
7776 
7777  for(unsigned int a = 0; a < InactiveTrackVector.size(); a++)
7778  {
7779  TTrackElement CheckElement = Track->InactiveTrackElementAt(142, a);
7780  InactivePair = GetVectorPositionsFromInactiveTrackMap(7, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7781  if(!FoundFlag)
7782  {
7783  throw Exception("CheckMapAndInactiveTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7784  " in InactiveMap, Caller=" + (AnsiString)Caller);
7785  }
7786  if((InactivePair.first != a) && (InactivePair.second != a))
7787  {
7788  throw Exception("CheckMapAndInactiveTrack Error - InactiveMapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7789  (AnsiString)CheckElement.VLoc + " Inactive Map values=" + (AnsiString)InactivePair.first + " and " + (AnsiString)InactivePair.second +
7790  " InactiveTrackVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
7791  }
7792  }
7793  if(InactiveTrackVector.size() != InactiveTrack2MultiMap.size())
7794  {
7795  throw Exception("CheckMapAndInactiveTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7796  " Caller=" + (AnsiString)Caller);
7797  }
7798  Utilities->CallLogPop(539);
7799 }
7800 
7801 // ---------------------------------------------------------------------------
7802 
7803 void TTrack::CheckGapMap(int Caller) // test
7804 {
7805  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckGapMap");
7806  int Position1, Position2;
7807  TTrackElement TrackElement1, TrackElement2;
7808  TGapMapIterator GapMapPtr;
7809 
7810  if(!GapMap.empty())
7811  {
7812  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
7813  {
7814  int HLoc1 = GapMapPtr->first.first;
7815  int VLoc1 = GapMapPtr->first.second;
7816  int HLoc2 = GapMapPtr->second.first;
7817  int VLoc2 = GapMapPtr->second.second;
7818  if(!FindNonPlatformMatch(14, HLoc1, VLoc1, Position1, TrackElement1))
7819  {
7820  throw Exception("Failed to find H & V for gap1, GapMap in error");
7821  }
7822  if(!FindNonPlatformMatch(15, HLoc2, VLoc2, Position2, TrackElement2))
7823  {
7824  throw Exception("Failed to find H & V for gap2, GapMap in error");
7825  }
7826  if(TrackElementAt(17, Position1).TrackType != GapJump)
7827  {
7828  throw Exception("Element at Pos1 not a gap, GapMap in error");
7829  }
7830  if(TrackElementAt(18, Position2).TrackType != GapJump)
7831  {
7832  throw Exception("Element at Pos2 not a gap, GapMap in error");
7833  }
7834  }
7835  }
7836  unsigned int GapCount = 0;
7837 
7838  for(unsigned int a = 0; a < TrackVector.size(); a++)
7839  {
7840  TTrackElement CheckElement = Track->TrackElementAt(1355, a);
7841  if(CheckElement.TrackType == GapJump)
7842  {
7843  GapCount++;
7844  }
7845  }
7846  if((GapMap.size() * 2) != GapCount)
7847  {
7848  throw Exception("GapMap Error - Map Size * 2 =" + (AnsiString)(GapMap.size() * 2) + " GapCount=" + (AnsiString)GapCount + " Caller=" +
7849  (AnsiString)Caller);
7850  }
7851  Utilities->CallLogPop(540);
7852 }
7853 
7854 // ---------------------------------------------------------------------------
7855 
7856 void TTrack::SetElementID(int Caller, TTrackElement &TrackElement)
7857 {
7858  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetElementID," + TrackElement.LogTrack(5));
7859  if((TrackElement.HLoc == -2000000000) || (TrackElement.VLoc == -2000000000))
7860  {
7861  if(TrackFinished)
7862  {
7863  throw Exception("Error - TrackFinished with erase element still present");
7864  }
7865  Utilities->CallLogPop(541);
7866  return; // erased element, can't set ID
7867  }
7868  AnsiString IDString;
7869 
7870  if(TrackElement.HLoc < 0)
7871  {
7872  IDString = "N" + AnsiString(abs(TrackElement.HLoc)) + "-";
7873  }
7874  else
7875  {
7876  IDString = AnsiString(TrackElement.HLoc) + "-";
7877  }
7878  if(TrackElement.VLoc < 0)
7879  {
7880  IDString += "N" + AnsiString(abs(TrackElement.VLoc));
7881  }
7882  else
7883  {
7884  IDString += AnsiString(TrackElement.VLoc);
7885  }
7886  TrackElement.ElementID = IDString;
7887  Utilities->CallLogPop(542);
7888 }
7889 
7890 // ---------------------------------------------------------------------------
7891 
7892 int TTrack::GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
7893 {
7894 // e.g. "8-13", "00008-13", "N43-N127", etc
7895  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorPositionFromString," + String); //String was inside " marks, corrected at v2.13.0
7896  int DelimPos;
7897 try //try..catch added at v2.13.0 following Amon Sadler's error file received on 24/03/22, had N-113-5 rather than N113-5
7898  {
7899  for(int x = 1; x < String.Length() + 1; x++)
7900  {
7901  if(String.IsDelimiter("-", x))
7902  {
7903  DelimPos = x;
7904  break;
7905  }
7906  if(x == String.Length())
7907  {
7908  if(GiveMessages)
7909  {
7910  ShowMessage("Error in track element identifier: <" + String + "> - no delimiter");
7911  }
7912  Utilities->CallLogPop(543);
7913  return(-1);
7914  }
7915  }
7916  if(DelimPos == 1)
7917  {
7918  if(GiveMessages)
7919  {
7920  ShowMessage("Error in track element identifier: <" + String + "> - No Horizontal value");
7921  }
7922  Utilities->CallLogPop(544);
7923  return(-1);
7924  }
7925  if(DelimPos == String.Length())
7926  {
7927  if(GiveMessages)
7928  {
7929  ShowMessage("Error in track element identifier <" + String + "> - No Vertical value");
7930  }
7931  Utilities->CallLogPop(545);
7932  return(-1);
7933  }
7934  if((String[String.Length()] < '0') || (String[String.Length()] > '9'))
7935  {
7936  if(GiveMessages)
7937  {
7938  ShowMessage("Error in track element identifier <" + String + "> - Last value is not a number");
7939  }
7940  Utilities->CallLogPop(1508);
7941  return(-1);
7942  }
7943  int HLoc, VLoc;
7944 
7945  if(String.SubString(1, 1) != "N")
7946  {
7947  for(int x = 1; x < DelimPos; x++)
7948  {
7949  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7950  {
7951  if(GiveMessages)
7952  {
7953  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
7954  }
7955  Utilities->CallLogPop(546);
7956  return(-1);
7957  }
7958  }
7959  }
7960  if(String.SubString(1, 1) == "N")
7961  {
7962  for(int x = 2; x < DelimPos; x++)
7963  {
7964  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7965  {
7966  if(GiveMessages)
7967  {
7968  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
7969  }
7970  Utilities->CallLogPop(763);
7971  return(-1);
7972  }
7973  }
7974  }
7975  if(String.SubString(1, 1) == "N")
7976  {
7977  HLoc = -(String.SubString(2, DelimPos - 2).ToInt());
7978  }
7979  else
7980  {
7981  HLoc = String.SubString(1, DelimPos - 1).ToInt();
7982  }
7983  if(String.SubString(DelimPos + 1, 1) != "N")
7984  {
7985  for(int x = DelimPos + 1; x < String.Length() + 1; x++)
7986  {
7987  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7988  {
7989  if(GiveMessages)
7990  {
7991  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
7992  }
7993  Utilities->CallLogPop(547);
7994  return(-1);
7995  }
7996  }
7997  }
7998  if(String.SubString(DelimPos + 1, 1) == "N")
7999  {
8000  for(int x = DelimPos + 2; x < String.Length() + 1; x++)
8001  {
8002  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8003  {
8004  if(GiveMessages)
8005  {
8006  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
8007  }
8008  Utilities->CallLogPop(764);
8009  return(-1);
8010  }
8011  }
8012  }
8013  if(String.SubString(DelimPos + 1, 1) == "N")
8014  {
8015  VLoc = -(String.SubString(DelimPos + 2, String.Length() - DelimPos - 1).ToInt());
8016  }
8017  else
8018  {
8019  VLoc = String.SubString(DelimPos + 1, String.Length() - DelimPos).ToInt();
8020  }
8021  THVPair HVPair(HLoc, VLoc);
8022  TTrackMapIterator TrackMapPtr;
8023 
8024  TrackMapPtr = TrackMap.find(HVPair);
8025  if(TrackMapPtr == TrackMap.end())
8026  {
8027  if(GiveMessages)
8028  {
8029  ShowMessage("No track element corresponding to track element identifier: <" + String + ">");
8030  }
8031  Utilities->CallLogPop(548);
8032  return(-1);
8033  }
8034  Utilities->CallLogPop(549);
8035  return(TrackMapPtr->second);
8036  }
8037  catch(const Exception &e) //non-error catch - catches any errors not already caught above
8038  //(added at v2.13.0 following Amon Sadler's error file received on 24/03/22), had N-113-5 rather than N113-5
8039  {
8040  ShowMessage("Syntax error in track element identifier: <" + String + ">");
8041  Utilities->CallLogPop(2481);
8042  return(-1);
8043  }
8044 }
8045 
8046 // ---------------------------------------------------------------------------
8047 
8048 bool TTrack::CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
8049 /*
8050  True for linked properly at both ends
8051 */
8052 {
8053  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckFootCrossingLinks," + AnsiString(TrackElement.HLoc) + "," +
8054  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
8055  int HLoc = TrackElement.HLoc;
8056  int VLoc = TrackElement.VLoc;
8057 
8058  if((TrackElement.SpeedTag != 129) && (TrackElement.SpeedTag != 130) && (TrackElement.SpeedTag != 145) && (TrackElement.SpeedTag != 146))
8059  {
8060  Utilities->CallLogPop(1821);
8061  return(false);
8062  }
8063  if(TrackElement.SpeedTag == 129) // vertical footbridge
8064  {
8065  // check top connection
8066  if(!(InactiveMapCheck(1, HLoc, VLoc, 76) // top plat
8067  || InactiveMapCheck(2, HLoc, VLoc - 1, 96) // concourse
8068  || InactiveMapCheck(3, HLoc, VLoc - 1, 77) // bot plat
8069  || ActiveMapCheck(4, HLoc, VLoc - 1, 129))) // vert footbridge
8070  {
8071  Utilities->CallLogPop(550);
8072  return(false);
8073  }
8074  // check bottom connection
8075  else if(!(InactiveMapCheck(4, HLoc, VLoc, 77) // bot plat
8076  || InactiveMapCheck(5, HLoc, VLoc + 1, 96) // concourse
8077  || InactiveMapCheck(6, HLoc, VLoc + 1, 76) // top plat
8078  || ActiveMapCheck(1, HLoc, VLoc + 1, 129))) // vert footbridge
8079  {
8080  Utilities->CallLogPop(551);
8081  return(false);
8082  }
8083  }
8084  if(TrackElement.SpeedTag == 145) // vertical underpass
8085  {
8086  // check top connection
8087  if(!(InactiveMapCheck(13, HLoc, VLoc, 76) // top plat
8088  || InactiveMapCheck(14, HLoc, VLoc - 1, 96) // concourse
8089  || InactiveMapCheck(15, HLoc, VLoc - 1, 77) // bot plat
8090  || ActiveMapCheck(5, HLoc, VLoc - 1, 145))) // vert u'pass
8091  {
8092  Utilities->CallLogPop(2114);
8093  return(false);
8094  }
8095  // check bottom connection
8096  else if(!(InactiveMapCheck(16, HLoc, VLoc, 77) // bot plat
8097  || InactiveMapCheck(17, HLoc, VLoc + 1, 96) // concourse
8098  || InactiveMapCheck(18, HLoc, VLoc + 1, 76) // top plat
8099  || ActiveMapCheck(6, HLoc, VLoc + 1, 145))) // vert u'pass
8100  {
8101  Utilities->CallLogPop(2115);
8102  return(false);
8103  }
8104  }
8105  if(TrackElement.SpeedTag == 130) // hor footbridge
8106  {
8107  // check left connection
8108  if(!(InactiveMapCheck(19, HLoc, VLoc, 78) // left plat
8109  || InactiveMapCheck(20, HLoc - 1, VLoc, 96) // concourse
8110  || InactiveMapCheck(21, HLoc - 1, VLoc, 79) // right plat
8111  || ActiveMapCheck(2, HLoc - 1, VLoc, 130))) // hor footbridge
8112  {
8113  Utilities->CallLogPop(552);
8114  return(false);
8115  }
8116  // check right connection
8117  else if(!(InactiveMapCheck(22, HLoc, VLoc, 79) // right plat
8118  || InactiveMapCheck(23, HLoc + 1, VLoc, 96) // concourse
8119  || InactiveMapCheck(24, HLoc + 1, VLoc, 78) // left plat
8120  || ActiveMapCheck(3, HLoc + 1, VLoc, 130))) // hor footbridge
8121  {
8122  Utilities->CallLogPop(553);
8123  return(false);
8124  }
8125  }
8126  if(TrackElement.SpeedTag == 146) // hor u'pass
8127  {
8128  // check left connection
8129  if(!(InactiveMapCheck(7, HLoc, VLoc, 78) // left plat
8130  || InactiveMapCheck(8, HLoc - 1, VLoc, 96) // concourse
8131  || InactiveMapCheck(9, HLoc - 1, VLoc, 79) // right plat
8132  || ActiveMapCheck(7, HLoc - 1, VLoc, 146))) // hor u'pass
8133  {
8134  Utilities->CallLogPop(2116);
8135  return(false);
8136  }
8137  // check right connection
8138  else if(!(InactiveMapCheck(10, HLoc, VLoc, 79) // right plat
8139  || InactiveMapCheck(11, HLoc + 1, VLoc, 96) // concourse
8140  || InactiveMapCheck(12, HLoc + 1, VLoc, 78) // left plat
8141  || ActiveMapCheck(8, HLoc + 1, VLoc, 146))) // hor u'pass
8142  {
8143  Utilities->CallLogPop(2117);
8144  return(false);
8145  }
8146  }
8147  Utilities->CallLogPop(554);
8148  return(true);
8149 }
8150 
8151 // ---------------------------------------------------------------------------
8152 
8153 bool TTrack::InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
8154 /*
8155  return true if the SpeedTag present in the map at H & V
8156 */
8157 {
8158  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8159  AnsiString(SpeedTag));
8160  if(InactiveTrack2MultiMap.empty())
8161  {
8162  Utilities->CallLogPop(555);
8163  return(false);
8164  }
8165  THVPair HVPair(HLoc, VLoc);
8167  TInactiveTrack2MultiMapIterator HVIt1 = IMEnd, HVIt2 = IMEnd;
8168  TInactiveTrackRange HVRange = InactiveTrack2MultiMap.equal_range(HVPair);
8169 
8170  if(HVRange.first == HVRange.second)
8171  {
8172  Utilities->CallLogPop(556);
8173  return(false);
8174  }
8175  else
8176  {
8177  HVIt1 = HVRange.first;
8178  }
8179  TTrackElement Temp1, Temp2; // test
8180 
8181  Temp1 = InactiveTrackElementAt(8, HVIt1->second); // test
8182  if(--HVRange.second != HVRange.first)
8183  {
8184  HVIt2 = HVRange.second;
8185  Temp2 = InactiveTrackElementAt(9, HVIt2->second); // test
8186  }
8187  if((InactiveTrackElementAt(10, HVIt1->second).SpeedTag == SpeedTag) || ((HVIt2 != IMEnd) && (InactiveTrackElementAt(11,
8188  HVIt2->second).SpeedTag == SpeedTag)))
8189  {
8190  Utilities->CallLogPop(557);
8191  return(true);
8192  }
8193  else
8194  {
8195  Utilities->CallLogPop(558);
8196  return(false);
8197  }
8198 }
8199 
8200 // ---------------------------------------------------------------------------
8201 
8202 bool TTrack::ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
8203 /*
8204  return true if the SpeedTag present in the map at H & V
8205 */
8206 {
8207  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ActiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8208  AnsiString(SpeedTag));
8209  if(TrackMap.empty())
8210  {
8211  Utilities->CallLogPop(559);
8212  return(false);
8213  }
8214  THVPair HVPair(HLoc, VLoc);
8215  TTrackMapIterator End = TrackMap.end();
8216  TTrackMapIterator It = End;
8217 
8218  It = TrackMap.find(HVPair);
8219  if((It != End) && (TrackElementAt(19, It->second).SpeedTag == SpeedTag))
8220  {
8221  Utilities->CallLogPop(560);
8222  return(true);
8223  }
8224  else
8225  {
8226  Utilities->CallLogPop(561);
8227  return(false);
8228  }
8229 }
8230 
8231 // ---------------------------------------------------------------------------
8232 
8233 void TTrack::EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
8234 {
8235 /*
8236  General:
8237  All platform, concourse, footcrossing & non-station named location elements are able to have a LocationName allocated, and track
8238  elements (including footcrossings) are able to have an ActiveTrackElementName allocated provided there is an adjacent platform or
8239  a NamedNonStationLocation.
8240  To set these names the user selects a single named location element (not a footcrossing), enters the name, and
8241  this is then allocated as a LocationName to all linked platform, concourse and footcrossing elements, and as an
8242  ActiveTrackElementName to all track elements adjacent to platforms (inc footcrossing tracks if (but only if) they have a
8243  platform at that location).
8244 
8245  Linked named location elements are those explained in TTrack::TTrack()
8246 
8247  Detail:
8248  Two containers are used for allocation of names - LNPendingList, and LNDone2MultiMap, each containing vector positions as
8249  integers and the Map using THVPairs as keys. An adjustment is made for the vector positions as follows:-
8250  inactive vector positions are stored as they are (since most NamedLocationElements are in the inactive vector), but active vector
8251  positions stored as (-1-True Position), so can hold both types in a single integer uniquely - not very elegant but it seems to
8252  work OK! e.g. TrackVector position 0 would be stored as -1, position n would be stored as -1-n. InactiveTrackVector position 0 would be stored as 0.
8253  To recover the true TrackVector position from a stored value the same rule applies, i.e. -1-stored value, equivalent to -1-(-1-original) = -1+1+original = original.
8254 
8255  The List holds elements that have still to be processed, and the Map holds elements that have been processed. On entering
8256  this function a single element should be in the List (normally from the user's selection but can also be from
8257  SearchForAndUpdateLocationName), and the Map is cleared within the function.
8258  A 'while' loop is entered if the List isn't empty, and the front element in it examined. All linked named location elements
8259  (platforms, concourses and footcrossings) that aren't already in either the Map or the List are first added to the List using
8260  AdjElement, then the element itself has it's LocationName set, and any relevant track elements at the same H & V (i.e. adjacent
8261  to a platform) have their ActiveTrackElementName set using AddName. The element is then inserted into the Map and erased from the List.
8262  In this way the list builds up while there are linked elements to be added, but reduces to zero when all are added and processing
8263  moves them into the Map. At the end all linked elements are in the Map.
8264 
8265  Finally any other element that isn't in the Map, i.e. not linked to the current named location, that has the same name as a
8266  LocationName or ActiveTrackElementName, has it erased. This is to allow for deletion of named location elements that split an existing
8267  named location - only one of the sides (selected by whichever the program finds first - the user can't select it) retains the name.
8268 */
8269 
8270 // AnsiString TestString = "H,V,Tag,List Size,DoneMultiMap Size,CurrentElementAddress,MultiMapEntryAddress";//test
8271 // Display->FileDiagnostics(TestString);//test
8272 
8273  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EnterLocationName," + LocationName);
8274  AnsiString TestString1, TestString2; // test
8275 
8276  Track->LNDone2MultiMap.clear();
8277  if(LNPendingList.size() != 1)
8278  {
8279  throw Exception("LNPendingList size not 1 on entry");
8280  }
8281  int CurrentElementNumber; //new after 2.4.3 due to error the JK found (Discord 9/7/20). See note below after 'if(AddingElements)' where CurrentElementNumber is used.
8282  while(!LNPendingList.empty())
8283  {
8284  CurrentElementNumber = LNPendingList.front();
8285  TTrackVectorIterator CurrentElement = GetTrackVectorIteratorFromNamePosition(1, CurrentElementNumber);
8286  int NewElement; // = 2000000000; //marker for unused //not needed from v1.2.0 Beta onwards
8287  int H = CurrentElement->HLoc;
8288  int V = CurrentElement->VLoc;
8289  int Tag = CurrentElement->SpeedTag;
8290  if(Tag == 76) // top plat
8291  {
8292  // AdjElement checks if there is an element matching Tag at H & V that isn't already in LNDone2MultiMap or LNPendingList,
8293  // & returns true if so with the adjusted vector position in NewElement. It checks the appropriate vector
8294  // depending on the SpeedTag value (footcrossings in active vector, rest in inactive vector),
8295  for(int x = 0; x < 25; x++)
8296  {
8297  if(AdjElement(1, H + Tag76Array[x][0], V + Tag76Array[x][1], Tag76Array[x][2], NewElement))
8298  {
8299  LNPendingList.insert(LNPendingList.end(), NewElement);
8300  }
8301  }
8302  }
8303  else if(Tag == 77) // bot plat
8304  {
8305  for(int x = 0; x < 25; x++)
8306  {
8307  if(AdjElement(2, H + Tag77Array[x][0], V + Tag77Array[x][1], Tag77Array[x][2], NewElement))
8308  {
8309  LNPendingList.insert(LNPendingList.end(), NewElement);
8310  }
8311  }
8312  }
8313  else if(Tag == 78) // l plat
8314  {
8315  for(int x = 0; x < 25; x++)
8316  {
8317  if(AdjElement(3, H + Tag78Array[x][0], V + Tag78Array[x][1], Tag78Array[x][2], NewElement))
8318  {
8319  LNPendingList.insert(LNPendingList.end(), NewElement);
8320  }
8321  }
8322  }
8323  else if(Tag == 79) // r plat
8324  {
8325  for(int x = 0; x < 25; x++)
8326  {
8327  if(AdjElement(4, H + Tag79Array[x][0], V + Tag79Array[x][1], Tag79Array[x][2], NewElement))
8328  {
8329  LNPendingList.insert(LNPendingList.end(), NewElement);
8330  }
8331  }
8332  }
8333  else if(Tag == 96) // conc
8334  {
8335  for(int x = 0; x < 28; x++)
8336  {
8337  if(AdjElement(5, H + Tag96Array[x][0], V + Tag96Array[x][1], Tag96Array[x][2], NewElement))
8338  {
8339  LNPendingList.insert(LNPendingList.end(), NewElement);
8340  }
8341  }
8342  }
8343  else if(Tag == 129) // vert footbridge
8344  {
8345  for(int x = 0; x < 8; x++)
8346  {
8347  if(AdjElement(6, H + Tag129Array[x][0], V + Tag129Array[x][1], Tag129Array[x][2], NewElement))
8348  {
8349  LNPendingList.insert(LNPendingList.end(), NewElement);
8350  }
8351  }
8352  }
8353  else if(Tag == 130) // hor footbridge
8354  {
8355  for(int x = 0; x < 8; x++)
8356  {
8357  if(AdjElement(7, H + Tag130Array[x][0], V + Tag130Array[x][1], Tag130Array[x][2], NewElement))
8358  {
8359  LNPendingList.insert(LNPendingList.end(), NewElement);
8360  }
8361  }
8362  }
8363  else if(Tag == 131) // named location
8364  {
8365  for(int x = 0; x < 4; x++)
8366  {
8367  if(AdjElement(8, H + Tag131Array[x][0], V + Tag131Array[x][1], Tag131Array[x][2], NewElement))
8368  {
8369  LNPendingList.insert(LNPendingList.end(), NewElement);
8370  }
8371  }
8372  }
8373  else if(Tag == 145) // v u'pass
8374  {
8375  for(int x = 0; x < 8; x++)
8376  {
8377  if(AdjElement(9, H + Tag145Array[x][0], V + Tag145Array[x][1], Tag145Array[x][2], NewElement))
8378  {
8379  LNPendingList.insert(LNPendingList.end(), NewElement);
8380  }
8381  }
8382  }
8383  else if(Tag == 146) // h u'pass
8384  {
8385  for(int x = 0; x < 8; x++)
8386  {
8387  if(AdjElement(10, H + Tag146Array[x][0], V + Tag146Array[x][1], Tag146Array[x][2], NewElement))
8388  {
8389  LNPendingList.insert(LNPendingList.end(), NewElement);
8390  }
8391  }
8392  }
8393  // below new at v1.1.0 but condition changed at v1.1.4 as interfered with name changes for single element locations
8394 // if(NewElement != 2000000000) //adjacent element found & new element inserted, check if a (different) name already allocated and if so erase it from text vector
8395  if(AddingElements)
8396  {
8397  int HPos, VPos; // not used but needed for FindText function
8398  if(CurrentElementNumber > -1) //up to & including 2.4.2 this was NewElement, which was the last one added during LNPendingList building above, so it could be
8399  //repeatedly selected rather than the element under examination (LNPendingList.front()) & the front element text name wouldn't be erased.
8400  //Using CurrentElementNumber ensures that all elements are examined & have names erased if present
8401  {
8402  AnsiString ExistingName = InactiveTrackElementAt(118, CurrentElementNumber).LocationName; //existing name of CurrentElement
8403  if((ExistingName != "") && (ExistingName != LocationName))
8404  {
8405  if(LocationNameMultiMap.find(ExistingName) == Track->LocationNameMultiMap.end())
8406  {
8407  } // name not in LocationNameMultiMap, so don't erase from TextVector
8408  else if(TextHandler->FindText(4, ExistingName, HPos, VPos)) // can't use 'EraseLocationNameText' as that function is in TInterface
8409  {
8410  if(TextHandler->TextErase(10, HPos, VPos, ExistingName))
8411  {
8412  ;
8413  } // condition not used
8414 
8415  }
8416  }
8417  }
8418  }
8419  AddName(1, CurrentElement, LocationName); // add location name to current element, + timetable name to any
8420  // track at that loc
8421  THVPair HVPair(H, V);
8422  TLNDone2MultiMapEntry LNDone2MultiMapEntry;
8423  LNDone2MultiMapEntry.first = HVPair;
8424  LNDone2MultiMapEntry.second = LNPendingList.front();
8425  LNDone2MultiMap.insert(LNDone2MultiMapEntry);
8426  LNPendingList.erase(LNPendingList.begin());
8427  }
8428 
8429 // search all name multimap for same name where corresponding active elements don't appear in
8430 // LNDone2MultiMap & erase the name for all elements at that H & V in both active & inactive vectors
8431 
8432  TLocationNameMultiMapIterator SNIterator;
8433  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8434  bool FoundFlag, ErasedFlag = false;
8435 
8436  if(SNRange.first != SNRange.second)
8437  {
8438  SNRange.first--; // now pointing to before the first
8439  SNRange.second--; // now pointing to the last
8440  for(SNIterator = SNRange.second; SNIterator != SNRange.first; SNIterator--)
8441  {
8442  // Same elements are in Done map as in name map
8443  if(!ElementInLNDone2MultiMap(1, SNIterator->second))
8444  {
8445  ErasedFlag = true;
8446  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(2, SNIterator->second);
8447  TVIt->LocationName = "";
8448  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
8449  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform)
8450  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
8451  {
8452  int Position = GetVectorPositionFromTrackMap(17, TVIt->HLoc, TVIt->VLoc, FoundFlag);
8453  if(FoundFlag)
8454  {
8455  TrackElementAt(20, Position).LocationName = "";
8456  TrackElementAt(21, Position).ActiveTrackElementName = "";
8457  }
8458  }
8459  // erase name in name map
8460 // ChangeLocationNameMultiMapEntry("", SNIterator); can't use this as interferes with the iterators
8461  }
8462  }
8463  }
8464  if(ErasedFlag)
8465  {
8467  }
8468  if(TrackFinished)
8469  {
8471  }
8472 // set here as well as in LinkTrack so don't have to link track just because a name added
8473 // if track not finished then will be set when track validated
8474 
8475 // Rebuild ContinuationNameMap - added at v2.6.1 due to error found by Andrekoener & notified by discord on 16/12/20
8476 // error was that if a continuation name was changed and a timetable stopping place included that new name then ContinuationNameMap wouldn't be rebuilt
8477 // so the timetable would validate and load and the name would appear in the dropdown list. The reason was that ContinuationNameMap was only built in TryToLinkTrack,
8478 // so if that isn't called (as it isn't for a name change) then the error wouldn't be seen. However next time the railway was loaded TryToLinkTrack was called
8479 // so the error would be seen.
8480 // This inclusion rebuilds ContinuationNameMap whenever a name is entered or changed so the error can no longer be hidden.
8481  std::pair<AnsiString, char>TempMapPair;
8482 
8483  ContinuationNameMap.clear();
8484  for(int x = 0; x < Track->TrackVectorSize(); x++)
8485  {
8486  if((Track->TrackElementAt(1356, x).TrackType == Continuation) && (Track->TrackElementAt(1357, x).ActiveTrackElementName != ""))
8487  {
8488  TempMapPair.first = Track->TrackElementAt(1358, x).ActiveTrackElementName;
8489  TempMapPair.second = 'x'; // unused
8490  ContinuationNameMap.insert(TempMapPair);
8491  }
8492  }
8493 //end of addition
8494  CheckLocationNameMultiMap(1); // test
8495  Utilities->CallLogPop(562);
8496 }
8497 
8498 // ---------------------------------------------------------------------------
8499 
8500 bool TTrack::AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
8501 /*
8502  Looks for a FixedNamedLocationElement at H & V with SpeedTag, and if found and not already present in either the
8503  LNDone2MultiMap or the LNPendingList returns an int corresponding to the adjusted vector position.
8504 */
8505 {
8506  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8507  AnsiString(SpeedTag));
8508  if(!NamedLocationElementAt(2, HLoc, VLoc))
8509  {
8510  Utilities->CallLogPop(948);
8511  return(false);
8512  }
8513  bool FoundFlag;
8514  int Position = -1;
8515  TIMPair IMPair;
8516 
8517  if((SpeedTag == 129) || (SpeedTag == 130) || (SpeedTag == 145) || (SpeedTag == 146)) // footcrossing - only in active vector
8518  {
8519  Position = GetVectorPositionFromTrackMap(18, HLoc, VLoc, FoundFlag);
8520  if(FoundFlag)
8521  {
8522  if(TrackElementAt(22, Position).SpeedTag == SpeedTag)
8523  {
8524  int MapPos = -1 - Position; // MapPos is the adjusted entry in the list & map
8525  if(!ElementInLNDone2MultiMap(2, MapPos) && !ElementInLNPendingList(1, MapPos))
8526  // don't allow duplicates in either list, or processing takes a lot longer
8527  {
8528  FoundElement = MapPos;
8529  Utilities->CallLogPop(563);
8530  return(true);
8531  }
8532  }
8533  }
8534  }
8535  else
8536  {
8537  IMPair = GetVectorPositionsFromInactiveTrackMap(8, HLoc, VLoc, FoundFlag);
8538  if(FoundFlag)
8539  {
8540  if(InactiveTrackElementAt(12, IMPair.first).SpeedTag == SpeedTag)
8541  {
8542  if(!ElementInLNDone2MultiMap(3, IMPair.first) && !ElementInLNPendingList(2, IMPair.first))
8543  {
8544  FoundElement = IMPair.first;
8545  Utilities->CallLogPop(564);
8546  return(true);
8547  }
8548  }
8549  else if(InactiveTrackElementAt(13, IMPair.second).SpeedTag == SpeedTag)
8550  {
8551  if(!ElementInLNDone2MultiMap(4, IMPair.second) && !ElementInLNPendingList(3, IMPair.second))
8552  {
8553  FoundElement = IMPair.second;
8554  Utilities->CallLogPop(565);
8555  return(true);
8556  }
8557  }
8558  }
8559  }
8560  Utilities->CallLogPop(566);
8561  return(false);
8562 }
8563 
8564 // ---------------------------------------------------------------------------
8565 
8566 void TTrack::AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
8567 /*
8568  Add location name to TrackElement and ActiveTrackElementName to any elements in trackmap
8569  at same H & V if TrackElement is a Platform or named non-station location. Also update LocationNameMultiMap
8570  with the new name
8571 */
8572 {
8573  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddName," + TrackElement->LogTrack(6) + "," + Name);
8574  AnsiString OldName = TrackElement->LocationName, ErrorString; // declare new AnsiStrings OldName (set to existing name) & ErrorString
8575 
8576  TrackElement->LocationName = Name; // covers all FixedNamedLocationElement whichever vector they are in
8577  int HLoc = TrackElement->HLoc;
8578  int VLoc = TrackElement->VLoc;
8579  bool FoundFlag;
8580 
8581  if((TrackElement->TrackType == Platform) || (TrackElement->TrackType == NamedNonStationLocation))
8582  // only have timetable names for adjacent platforms & named locations
8583  {
8584  int Position = GetVectorPositionFromTrackMap(19, HLoc, VLoc, FoundFlag);
8585  if(FoundFlag)
8586  {
8587  TrackElementAt(23, Position).ActiveTrackElementName = Name;
8588  }
8589  }
8590  TLocationNameMultiMapIterator SNIterator = FindNamedElementInLocationNameMultiMap(4, OldName, TrackElement, ErrorString);
8591 
8592  if(ErrorString != "")
8593  {
8594  throw Exception(ErrorString + " in AddName for OldName == " + OldName);
8595  }
8596  ChangeLocationNameMultiMapEntry(1, Name, SNIterator); // OK, can use it here as not in an iterator loop
8597  CheckLocationNameMultiMap(2); // test
8598  Utilities->CallLogPop(567);
8599 }
8600 
8601 // ---------------------------------------------------------------------------
8602 
8603 bool TTrack::ElementInLNDone2MultiMap(int Caller, int MapPos)
8604 /*
8605  Examines LNDone2MultiMap to see whether the MapPos value is present, and returns true if so.
8606 */
8607 {
8608  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNDone2MultiMap," + AnsiString(MapPos));
8609  if(LNDone2MultiMap.empty())
8610  {
8611  Utilities->CallLogPop(568);
8612  return(false);
8613  }
8614  TLNDone2MultiMapIterator LNDone2MultiMapIterator;
8615 
8616  for(LNDone2MultiMapIterator = LNDone2MultiMap.begin(); LNDone2MultiMapIterator != LNDone2MultiMap.end(); LNDone2MultiMapIterator++)
8617  {
8618  if(LNDone2MultiMapIterator->second == MapPos)
8619  {
8620  Utilities->CallLogPop(569);
8621  return(true);
8622  }
8623  }
8624  Utilities->CallLogPop(570);
8625  return(false);
8626 }
8627 
8628 // ---------------------------------------------------------------------------
8629 
8630 bool TTrack::ElementInLNPendingList(int Caller, int MapPos)
8631 /*
8632  Examines LNPendingList to see whether the MapPos value is present, and returns true if so.
8633 */
8634 {
8635  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNPendingList," + AnsiString(MapPos));
8636  if(LNPendingList.empty())
8637  {
8638  Utilities->CallLogPop(571);
8639  return(false);
8640  }
8641  TLNPendingListIterator LNPendingListIterator;
8642 
8643  for(LNPendingListIterator = LNPendingList.begin(); LNPendingListIterator != LNPendingList.end(); LNPendingListIterator++)
8644  {
8645  if(*LNPendingListIterator == MapPos)
8646  {
8647  Utilities->CallLogPop(572);
8648  return(true);
8649  }
8650  }
8651  Utilities->CallLogPop(573);
8652  return(false);
8653 }
8654 
8655 // ---------------------------------------------------------------------------
8656 
8657 bool TTrack::NamedLocationElementAt(int Caller, int HLoc, int VLoc)
8658 /*
8659  Examines element at H & V, and returns true if its FixedNamedLocationElement bool is true
8660 */
8661 {
8662  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NamedLocationElementAt," + AnsiString(HLoc) + "," + AnsiString(VLoc));
8663  THVPair HVPair(HLoc, VLoc);
8664  TTrackMapIterator TrackMapPtr = TrackMap.find(HVPair);
8665  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(HVPair);
8666 
8667  if(TrackMapPtr != TrackMap.end()) // =end() if not found
8668  {
8669  if(TrackElementAt(24, TrackMapPtr->second).FixedNamedLocationElement)
8670  {
8671  Utilities->CallLogPop(574);
8672  return(true);
8673  }
8674  }
8675  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
8676  // may be 2 platforms at location but if so both FixedNamedLocationElement bools will be set, so only need to find one
8677  {
8678  if(InactiveTrackElementAt(14, InactiveTrack2MultiMapIterator->second).FixedNamedLocationElement)
8679  {
8680  Utilities->CallLogPop(575);
8681  return(true);
8682  }
8683  }
8684  Utilities->CallLogPop(576);
8685  return(false);
8686 }
8687 
8688 // ---------------------------------------------------------------------------
8689 
8690 bool TTrack::LocationNameAllocated(int Caller, AnsiString LocationName) // true if a non-empty LocationName found in LocationNameMultiMap
8691 {
8692  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationNameAllocated," + LocationName);
8693  if(Track->LocationNameMultiMap.find(LocationName) != Track->LocationNameMultiMap.end())
8694  {
8695  Utilities->CallLogPop(1953);
8696  return(true);
8697  }
8698  Utilities->CallLogPop(1954);
8699  return(false);
8700 }
8701 
8702 // ---------------------------------------------------------------------------
8703 
8704 bool TTrack::DuplicatedLocationName(int Caller, bool GiveMessage)
8705 //examines LocationNameMultiMap and returns true if there are two or more locations with the same name - added at v2.6.1 to cater for Bill78's new .dev file merge
8706 //program and used when try to save as a .rly file
8707 {
8708  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DuplicatedLocationName");
8711  if(LocationNameMultiMap.empty()) //no names so no duplicates
8712  {
8713  Utilities->CallLogPop(2254);
8714  return(false);
8715  }
8716  AnsiString NameBeingChecked = LocationNameMultiMap.begin()->first; //first name to start with
8717  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked);
8718  if(NameBeingChecked != "") //added for v2.6.2 as 2.6.1 reported duplicate null names (reported by Micke(Commuterpop) 06/01/21 via discord)
8719  {
8721  {
8722  if(GiveMessage)
8723  {
8724  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8725  }
8726  Utilities->CallLogPop(2255);
8727  return(true);
8728  }
8729  }
8730  while(LNMMRg.second != LocationNameMultiMap.end()) //here LNMMRg still set to earlier name
8731  {
8732  NameBeingChecked = LNMMRg.second->first; //this is the next name as LNMMRg->second points to the first location NOT containing the first name
8733  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked); //here LNMMRg is the new range
8734  if(NameBeingChecked != "") //should have skipped all null names as all listed together but add to be on the safe side
8735  {
8737  {
8738  if(GiveMessage)
8739  {
8740  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8741  }
8742  Utilities->CallLogPop(2256);
8743  return(true);
8744  }
8745  }
8746  }
8747  Utilities->CallLogPop(2257);
8748  return(false); //OK, no duplicates
8749 }
8750 
8751 // ---------------------------------------------------------------------------
8752 
8754 {
8755  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateHVPairsLinkedMapAndNoDuplicates");
8756  THVPair HVPair;
8757  THVPairsLinkedMap HVPairsLinkedMap; //this is a map of HVPairs (so each is unique), each with a boolean marker, false for not linked and true for linked
8758  //for use in the duplicate check
8759  for(TLocationNameMultiMapIterator LNMMIt = LNMMRg.first; LNMMIt != LNMMRg.second; LNMMIt++) //populating the linked map
8760  {
8761  if(LNMMIt->second < 0) //active track element
8762  {
8763  HVPair.first = TrackElementAt(1011, (-1 - LNMMIt->second)).HLoc;
8764  HVPair.second = TrackElementAt(1012, (-1 - LNMMIt->second)).VLoc;
8765  }
8766  else //inactive track element
8767  {
8768  HVPair.first = InactiveTrackElementAt(134, LNMMIt->second).HLoc;
8769  HVPair.second = InactiveTrackElementAt(135, LNMMIt->second).VLoc;
8770  }
8771  HVPairsLinkedMap.insert(std::pair<THVPair, bool>(HVPair, false)); //set all bools to false initially
8772  }
8773  //All HVPairs now present in HVPairsLinkedMap for the specific location name
8774 
8775  //now need to identify all named elements that are linked either vertically or horizontally with the first one (could be any but must be just one)
8776  //so that at the end any that haven't been identified aren't linked and so represent a duplicated name
8777  //to do so need a list (works like LNPendingList) to hold all elements that haven't been checked for links
8778 
8779  std::list<THVPair> HVLinkedList;
8780 
8781  //set the first value to true and add it to the list
8782  HVPairsLinkedMap.begin()->second = true;
8783  HVLinkedList.push_back(HVPairsLinkedMap.begin()->first);
8784  //now enter a loop to examine the front pair in the list and set all linked bools to true, and if they weren't already true then add them to the back of the list for later
8785  //examination
8786  THVPair HVPairUnderExamination;
8787  THVPairsLinkedMap::iterator HVPLMIt;
8788  THVPair HVPairNew;
8789  while(!HVLinkedList.empty())
8790  {
8791  HVPairUnderExamination = HVLinkedList.front();
8792  HVLinkedList.pop_front();
8793  HVPairNew.first = HVPairUnderExamination.first;
8794  HVPairNew.second = HVPairUnderExamination.second - 1; //position directly above element
8795  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8796  if(HVPLMIt != HVPairsLinkedMap.end())
8797  {
8798  if(!HVPLMIt->second)
8799  {
8800  HVLinkedList.push_back(HVPLMIt->first);
8801  }
8802  HVPLMIt->second = true;
8803  }
8804  HVPairNew.first = HVPairUnderExamination.first - 1;
8805  HVPairNew.second = HVPairUnderExamination.second; //position to the left of the element
8806  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8807  if(HVPLMIt != HVPairsLinkedMap.end())
8808  {
8809  if(!HVPLMIt->second)
8810  {
8811  HVLinkedList.push_back(HVPLMIt->first);
8812  }
8813  HVPLMIt->second = true;
8814  }
8815  HVPairNew.first = HVPairUnderExamination.first;
8816  HVPairNew.second = HVPairUnderExamination.second + 1; //position under the element
8817  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8818  if(HVPLMIt != HVPairsLinkedMap.end())
8819  {
8820  if(!HVPLMIt->second)
8821  {
8822  HVLinkedList.push_back(HVPLMIt->first);
8823  }
8824  HVPLMIt->second = true;
8825  }
8826  HVPairNew.first = HVPairUnderExamination.first + 1;
8827  HVPairNew.second = HVPairUnderExamination.second; //position to the right of the element
8828  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8829  if(HVPLMIt != HVPairsLinkedMap.end())
8830  {
8831  if(!HVPLMIt->second)
8832  {
8833  HVLinkedList.push_back(HVPLMIt->first);
8834  }
8835  HVPLMIt->second = true;
8836  }
8837  }
8838 
8839  //at the end if any have a false bool then the name is duplicated so return false
8840  for(THVPairsLinkedMap::iterator HVPLMIt = HVPairsLinkedMap.begin(); HVPLMIt != HVPairsLinkedMap.end(); HVPLMIt++)
8841  {
8842  if(!HVPLMIt->second)
8843  {
8844  Utilities->CallLogPop(2258);
8845  return(false);
8846  }
8847  }
8848  Utilities->CallLogPop(2259);
8849  return(true);
8850 }
8851 
8852 // ---------------------------------------------------------------------------
8853 
8854 bool TTrack::TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
8855 /*
8856  Examines ActiveTrackElementNameMap and returns true if the LocationName is found and isn't "" (used to use LocationNameMultiMap)
8857 */
8858 
8859 {
8860  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TimetabledLocationNameAllocated," + LocationName);
8861  if(LocationName == "")
8862  {
8863  Utilities->CallLogPop(577);
8864  return(false);
8865  }
8866 // new for v0.2b
8867 // compile ActiveTrackElementNameMap if !ActiveTrackElementNameMapCompiledFlag (added as a precaution, should be compiled when reach here)
8869  {
8870  TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
8871  ActiveTrackElementNameMap.clear();
8872  for(unsigned int x = 0; x < TrackVector.size(); x++)
8873  {
8874  if((TrackElementAt(1359, x).ActiveTrackElementName != "") && (ContinuationNameMap.find(TrackElementAt(1360, x).ActiveTrackElementName))
8875  == ContinuationNameMap.end())
8876  {
8877  // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
8878  ActiveTrackElementNameMapEntry.first = Track->TrackElementAt(1361, x).ActiveTrackElementName;
8879  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
8880  ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
8881  }
8882  }
8884  }
8885  Utilities->CallLogPop(578);
8886  return (ActiveTrackElementNameMap.find(LocationName) != ActiveTrackElementNameMap.end());
8887 // end of new section
8888 // return (LocationNameMultiMap.find(LocationName) != LocationNameMultiMap.end());
8889 }
8890 
8891 // ---------------------------------------------------------------------------
8892 
8893 void TTrack::EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
8894 /*
8895  Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both active and inactive vectors) have the
8896  name erased both as a LocationName and a ActiveTrackElementName. The LocationNameMultiMap is also rebuilt to correspond to the
8897  new names in the vectors.
8898 */
8899 {
8900  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationAndActiveTrackElementNames," + LocationName);
8901  bool FoundFlag, ErasedFlag = false;
8902  TLocationNameMultiMapIterator SNIterator;
8903  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8904 
8905  if(SNRange.first != SNRange.second)
8906  {
8907  ErasedFlag = true;
8908  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
8909  {
8910  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(3, SNIterator->second);
8911  TVIt->LocationName = "";
8912  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
8913  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform or namedlocation)
8914  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
8915  {
8916  int Position = GetVectorPositionFromTrackMap(20, TVIt->HLoc, TVIt->VLoc, FoundFlag);
8917  if(FoundFlag)
8918  {
8919  TrackElementAt(25, Position).LocationName = "";
8920  TrackElementAt(26, Position).ActiveTrackElementName = "";
8921  }
8922  }
8923  }
8924  }
8925  if(ErasedFlag)
8926  {
8928  }
8929  CheckLocationNameMultiMap(3); // test
8930  Utilities->CallLogPop(579);
8931 }
8932 
8933 // ---------------------------------------------------------------------------
8934 
8935 void TTrack::SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
8936 /*
8937  NB No longer used during EraseTrackElement, too long-winded - erase all name now if any part removed, user needs to re-enter
8938  Checks all locations that are adjacent to the one entered for linked named location elements, and if any LocationName is found
8939  in any of the linked elements that name is used for all elements that are now linked to it. The location entered doesn't
8940  need to be a FixedNamedLocationElement and there doesn't even need to be an element there. Used during EraseTrackElement (in which
8941  case the SpeedTag is that for the element that is erased) and PlotAndAddTrackElement, to bring the named location and timetable
8942  naming up to date with the deletion or insertion.
8943 */
8944 {
8945  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForAndUpdateLocationName," + AnsiString(HLoc) + "," +
8946  AnsiString(VLoc) + "," + AnsiString(SpeedTag));
8947  LNPendingList.clear();
8948  AnsiString LocationName;
8949  int MapPos;
8950  bool FoundFlag = 0;
8951 
8952 //first check if this element is inactive and named, and if so use its position and name (new at v2.6.0 to allow pasted named locations to name linked elements)
8953  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(30, HLoc, VLoc, FoundFlag);
8954  if(FoundFlag)
8955  {
8956  LocationName = InactiveTrackElementAt(132, IMPair.first).LocationName;
8957  if(LocationName != "")
8958  {
8959  LNPendingList.insert(Track->LNPendingList.end(), IMPair.first);
8960  EnterLocationName(13, LocationName, true);
8961  Utilities->CallLogPop(2251);
8962  return;
8963  }
8964  LocationName = InactiveTrackElementAt(133, IMPair.second).LocationName;
8965  if(LocationName != "")
8966  {
8967  LNPendingList.insert(Track->LNPendingList.end(), IMPair.second);
8968  EnterLocationName(14, LocationName, true);
8969  Utilities->CallLogPop(2252);
8970  return;
8971  }
8972  }
8973 //then check if this element is active and named, and if so use its position (-Pos-1) and name (new at v2.6.0 to allow pasted named locations to name linked elements)
8974 
8975  int Position = GetVectorPositionFromTrackMap(59, HLoc, VLoc, FoundFlag);
8976  if(FoundFlag)
8977  {
8978  LocationName = TrackElementAt(1004, Position).LocationName;
8979  if(LocationName != "")
8980  {
8981  int ModifiedPosition = -1 - Position;
8982  LNPendingList.insert(Track->LNPendingList.end(), ModifiedPosition);
8983  EnterLocationName(15, LocationName, true);
8984  Utilities->CallLogPop(2253);
8985  return;
8986  }
8987  }
8988  if(SpeedTag == 76) // top plat
8989  {
8990  for(int x = 0; x < 25; x++)
8991  {
8992  if(AdjNamedElement(1, HLoc + Tag76Array[x][0], VLoc + Tag76Array[x][1], Tag76Array[x][2], LocationName, MapPos))
8993  {
8994  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8995  EnterLocationName(3, LocationName, true);
8996  break;
8997  }
8998  }
8999  }
9000  else if(SpeedTag == 77) // bot plat
9001  {
9002  for(int x = 0; x < 25; x++)
9003  {
9004  if(AdjNamedElement(2, HLoc + Tag77Array[x][0], VLoc + Tag77Array[x][1], Tag77Array[x][2], LocationName, MapPos))
9005  {
9006  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9007  EnterLocationName(4, LocationName, true);
9008  break;
9009  }
9010  }
9011  }
9012  else if(SpeedTag == 78) // l plat
9013  {
9014  for(int x = 0; x < 25; x++)
9015  {
9016  if(AdjNamedElement(3, HLoc + Tag78Array[x][0], VLoc + Tag78Array[x][1], Tag78Array[x][2], LocationName, MapPos))
9017  {
9018  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9019  EnterLocationName(5, LocationName, true);
9020  break;
9021  }
9022  }
9023  }
9024  else if(SpeedTag == 79) // r plat
9025  {
9026  for(int x = 0; x < 25; x++)
9027  {
9028  if(AdjNamedElement(4, HLoc + Tag79Array[x][0], VLoc + Tag79Array[x][1], Tag79Array[x][2], LocationName, MapPos))
9029  {
9030  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9031  EnterLocationName(6, LocationName, true);
9032  break;
9033  }
9034  }
9035  }
9036  else if(SpeedTag == 96) // conc
9037  {
9038  for(int x = 0; x < 28; x++)
9039  {
9040  if(AdjNamedElement(5, HLoc + Tag96Array[x][0], VLoc + Tag96Array[x][1], Tag96Array[x][2], LocationName, MapPos))
9041  {
9042  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9043  EnterLocationName(7, LocationName, true);
9044  break;
9045  }
9046  }
9047  }
9048  else if(SpeedTag == 129) // vert footbridge
9049  {
9050  for(int x = 0; x < 8; x++)
9051  {
9052  if(AdjNamedElement(6, HLoc + Tag129Array[x][0], VLoc + Tag129Array[x][1], Tag129Array[x][2], LocationName, MapPos))
9053  {
9054  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9055  EnterLocationName(8, LocationName, true);
9056  break;
9057  }
9058  }
9059  }
9060  else if(SpeedTag == 130) // hor footbridge
9061  {
9062  for(int x = 0; x < 8; x++)
9063  {
9064  if(AdjNamedElement(7, HLoc + Tag130Array[x][0], VLoc + Tag130Array[x][1], Tag130Array[x][2], LocationName, MapPos))
9065  {
9066  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9067  EnterLocationName(9, LocationName, true);
9068  break;
9069  }
9070  }
9071  }
9072  else if(SpeedTag == 145) // vert u'pass
9073  {
9074  for(int x = 0; x < 8; x++)
9075  {
9076  if(AdjNamedElement(9, HLoc + Tag145Array[x][0], VLoc + Tag145Array[x][1], Tag145Array[x][2], LocationName, MapPos))
9077  {
9078  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9079  EnterLocationName(11, LocationName, true);
9080  break;
9081  }
9082  }
9083  }
9084  else if(SpeedTag == 146) // hor u'pass
9085  {
9086  for(int x = 0; x < 8; x++)
9087  {
9088  if(AdjNamedElement(10, HLoc + Tag146Array[x][0], VLoc + Tag146Array[x][1], Tag146Array[x][2], LocationName, MapPos))
9089  {
9090  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9091  EnterLocationName(12, LocationName, true);
9092  break;
9093  }
9094  }
9095  }
9096  else if(SpeedTag == 131) // named location
9097  {
9098  for(int x = 0; x < 4; x++)
9099  {
9100  if(AdjNamedElement(8, HLoc + Tag131Array[x][0], VLoc + Tag131Array[x][1], Tag131Array[x][2], LocationName, MapPos))
9101  {
9102  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9103  EnterLocationName(10, LocationName, true);
9104  break;
9105  }
9106  }
9107  }
9108 // AddName(HLoc, VLoc, LocationName);//don't need this now, EnterLocationName takes care of it
9109  Utilities->CallLogPop(580);
9110 }
9111 
9112 // ---------------------------------------------------------------------------
9113 
9114 bool TTrack::AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
9115 /*
9116  Used in SearchForAndUpdateLocationName to check for elements in TrackMap & InactiveTrackMap that match H, V & Tag, & returns
9117  true if a LocationName is found, and also returns the name and the adjusted vector position.
9118 */
9119 {
9120  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjNamedElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
9121  AnsiString(SpeedTag));
9122  bool FoundFlag;
9123  TIMPair IMPair;
9124  TTrackVectorIterator TempElement;
9125  int Position;
9126 
9127  IMPair = GetVectorPositionsFromInactiveTrackMap(9, HLoc, VLoc, FoundFlag);
9128  if(FoundFlag)
9129  {
9130  if(InactiveTrackElementAt(15, IMPair.first).SpeedTag == SpeedTag)
9131  {
9132  TempElement = InactiveTrackVector.begin() + IMPair.first;
9133  if(TempElement->LocationName != "")
9134  {
9135  LocationName = TempElement->LocationName;
9136  FoundElement = IMPair.first;
9137  Utilities->CallLogPop(581);
9138  return(true);
9139  }
9140  }
9141  else if(InactiveTrackElementAt(16, IMPair.second).SpeedTag == SpeedTag)
9142  {
9143  TempElement = InactiveTrackVector.begin() + IMPair.second;
9144  if(TempElement->LocationName != "")
9145  {
9146  LocationName = TempElement->LocationName;
9147  FoundElement = IMPair.second;
9148  Utilities->CallLogPop(582);
9149  return(true);
9150  }
9151  }
9152  }
9153  Position = GetVectorPositionFromTrackMap(21, HLoc, VLoc, FoundFlag);
9154  if(FoundFlag)
9155  {
9156  if(TrackElementAt(27, Position).SpeedTag == SpeedTag)
9157  {
9158  TempElement = TrackVector.begin() + Position;
9159  if(TempElement->LocationName != "")
9160  {
9161  LocationName = TempElement->LocationName;
9162  FoundElement = -1 - Position;
9163  Utilities->CallLogPop(583);
9164  return(true);
9165  }
9166  }
9167  }
9168  Utilities->CallLogPop(584);
9169  return(false);
9170 }
9171 
9172 // ---------------------------------------------------------------------------
9173 
9174 void TTrack::CheckLocationNameMultiMap(int Caller) // test function
9175 {
9176 // check quantity in map & vectors match
9177  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckLocationNameMultiMap,");
9178  unsigned int Count = 0;
9179 
9180  if(SkipLocationNameMultiMapCheck) // renamed in v2.4.0 to skip check when pasting because fails as map elements not fully aligned until all pasted
9181  {
9182  Utilities->CallLogPop(2059);
9183  return;
9184  }
9185  AnsiString SName, TName, ErrorString;
9186 
9187  for(unsigned int x = 0; x < TrackVector.size(); x++)
9188  {
9189  if(TrackElementAt(1362, x).FixedNamedLocationElement)
9190  {
9191  if(TrackElementAt(1363, x).TrackType != FootCrossing)
9192  {
9193  throw Exception("Track element has FixedNamedLocationElement set but is not a footbridge/underpass in CheckLocationNameMultiMap, caller = " +
9194  AnsiString(Caller));
9195  }
9196  Count++;
9197  }
9198  }
9199  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9200  {
9201  if(InactiveTrackElementAt(143, x).FixedNamedLocationElement)
9202  {
9203  if((InactiveTrackElementAt(144, x).TrackType != Platform) && (InactiveTrackElementAt(145, x).TrackType != NamedNonStationLocation) &&
9204  (InactiveTrackElementAt(146, x).TrackType != Concourse))
9205  {
9206  throw Exception
9207  ("Inactive track element has FixedNamedLocationElement set but is not a platform, concourse or named location in CheckLocationNameMultiMap, caller = " +
9208  AnsiString(Caller));
9209  }
9210  Count++;
9211  }
9212  }
9213  if(LocationNameMultiMap.size() != Count)
9214  {
9215  throw Exception("LocationNameMultiMap size = " + AnsiString(LocationNameMultiMap.size()) + " & Count = " + AnsiString(Count) +
9216  " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9217  }
9218 // check all entries in both vectors match entries in name multimap
9220 
9221  for(unsigned int x = 0; x < TrackVector.size(); x++)
9222  {
9223  if(TrackElementAt(1364, x).FixedNamedLocationElement)
9224  {
9225  SName = TrackElementAt(1365, x).LocationName;
9226  SNIt = FindNamedElementInLocationNameMultiMap(5, SName, TrackVector.begin() + x, ErrorString);
9227  if(ErrorString != "")
9228  {
9229  throw Exception(ErrorString + " in CheckLocationNameMultiMap for TrackVector check, caller = " + AnsiString(Caller));
9230  }
9231  if(SNIt->second != -1 - (int)x)
9232  {
9233  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9234  AnsiString(Caller));
9235  }
9236  }
9237  // check corresponding platform for all Timetable entries that aren't empty
9238  TName = TrackElementAt(1366, x).ActiveTrackElementName;
9239  TIMPair IMPair;
9240  bool FoundFlag = false;
9241  if(TName != "")
9242  {
9243  IMPair = GetVectorPositionsFromInactiveTrackMap(10, TrackElementAt(1367, x).HLoc, TrackElementAt(1368, x).VLoc, FoundFlag);
9244  if(FoundFlag)
9245  {
9246  if((InactiveTrackElementAt(17, IMPair.first).TrackType != Platform) && (InactiveTrackElementAt(18, IMPair.second).TrackType != Platform) &&
9248  {
9249  throw Exception("Track element with ActiveTrackElementName but no plat/named loc at H " + AnsiString(TrackElementAt(1369, x).HLoc) + " & V " +
9250  AnsiString(TrackElementAt(1370, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9251  }
9252  if((InactiveTrackElementAt(20, IMPair.first).LocationName != TName) && (InactiveTrackElementAt(21, IMPair.second).LocationName != TName))
9253  {
9254  throw Exception("Track element with ActiveTrackElementName " + TName + " but plat/named loc at H " + AnsiString(TrackElementAt(1371, x).HLoc) +
9255  " & V " + AnsiString(TrackElementAt(1372, x).VLoc) + " has different LocationName in CheckLocationNameMultiMap, caller = " +
9256  AnsiString(Caller));
9257  }
9258  }
9259  else
9260  {
9261  throw Exception("Track element with ActiveTrackElementName but no inactive element at H " + AnsiString(TrackElementAt(1373, x).HLoc) + " & V " +
9262  AnsiString(TrackElementAt(1374, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9263  }
9264  }
9265  }
9266  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9267  {
9268  if(InactiveTrackElementAt(147, x).FixedNamedLocationElement)
9269  {
9270  SName = InactiveTrackElementAt(148, x).LocationName;
9271  SNIt = FindNamedElementInLocationNameMultiMap(6, SName, InactiveTrackVector.begin() + x, ErrorString);
9272  if(ErrorString != "")
9273  {
9274  throw Exception(ErrorString + " in CheckLocationNameMultiMap for InactiveTrackVector check, caller = " + AnsiString(Caller));
9275  }
9276  if(SNIt->second != (int)x)
9277  {
9278  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9279  AnsiString(Caller));
9280  }
9281  }
9282  }
9283  Utilities->CallLogPop(585);
9284 }
9285 
9286 // ---------------------------------------------------------------------------
9287 
9289  AnsiString &ErrorString)
9290 {
9291 /*
9292  Searches the name map to check if the element pointed to by the TTrackVectorIterator has the name
9293  LocationName. If it finds it the pointer TLocationNameMultiMapIterator is returned. If it fails ErrorString
9294  is set to an appropriate text to allow the calling function to report the error. Otherwise it is set to "".
9295 */
9296  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNamedElementInLocationNameMultiMap," + LocationName + "," +
9297  AnsiString(TrackElement->HLoc) + "," + AnsiString(TrackElement->VLoc) + "," + AnsiString(TrackElement->SpeedTag));
9298  ErrorString = "";
9299  bool FoundFlag = false;
9300  TLocationNameMultiMapIterator SNIterator;
9301  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9302 
9303  if(SNRange.first == SNRange.second)
9304  {
9305  ErrorString = "Error, Name " + LocationName + " not found in map";
9306  Utilities->CallLogPop(586);
9307  return(SNRange.first);
9308  }
9309  else
9310  {
9311  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9312  {
9313  if(SNIterator->second < 0)
9314  {
9315  int TVPos = -1 - SNIterator->second;
9316  TTrackVectorIterator TVIt = TrackVector.begin() + TVPos;
9317  if(TVIt == TrackElement)
9318  {
9319  FoundFlag = true;
9320  Utilities->CallLogPop(587);
9321  return(SNIterator);
9322  }
9323  }
9324  else
9325  {
9326  int ITVPos = SNIterator->second;
9327  TTrackVectorIterator ITVIt = InactiveTrackVector.begin() + ITVPos;
9328  if(ITVIt == TrackElement)
9329  {
9330  FoundFlag = true;
9331  Utilities->CallLogPop(588);
9332  return(SNIterator);
9333  }
9334  }
9335  }
9336  }
9337  if(!FoundFlag)
9338  {
9339  ErrorString = "Error, Name " + LocationName + " found but not at required element";
9340  }
9341  Utilities->CallLogPop(589);
9342  return(SNIterator);
9343 }
9344 
9345 // ---------------------------------------------------------------------------
9346 
9347 void TTrack::ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
9348 {
9349 /*
9350  Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationNameMultiMapIterator
9351  from whatever it was before. Accepts null entries so that a formerly named element can have the name changed to "".
9352 */
9353  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ChangeLocationNameMultiMapEntry," + NewName);
9354  TLocationNameMultiMapEntry LocationNameEntry;
9355 
9356  LocationNameEntry.first = NewName;
9357  LocationNameEntry.second = SNIterator->second;
9358  LocationNameMultiMap.erase(SNIterator);
9359  LocationNameMultiMap.insert(LocationNameEntry);
9360  Utilities->CallLogPop(590);
9361 }
9362 
9363 // ---------------------------------------------------------------------------
9364 
9366 {
9367 // Takes an adjusted vector position value and returns a pointer to the relevant element. Can be in either vector.
9368  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorIteratorFromNamePosition," + AnsiString(Position));
9369  if(Position < 0) // footcrossing
9370  {
9371  int TruePos = -1 - Position;
9372  // new check at v0.2b
9373  if(TrackElementAt(817, TruePos).TrackType != FootCrossing)
9374  {
9375  throw Exception("Footbridge/underpass error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9376  }
9377  Utilities->CallLogPop(591);
9378  return (TrackVector.begin() + TruePos);
9379  }
9380  else
9381  {
9382  // new check at v0.2b
9383  if(!(InactiveTrackElementAt(99, Position).FixedNamedLocationElement))
9384  {
9385  throw Exception("Inactive element error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9386  }
9387  Utilities->CallLogPop(592);
9388  return (InactiveTrackVector.begin() + Position);
9389  }
9390 }
9391 
9392 // ---------------------------------------------------------------------------
9393 
9394 void TTrack::DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
9395 {
9396 /*
9397  After an element has been erased from the inactive track vector, all the later elements are moved down one. This function
9398  decrements the position values for all values above that of the erased element in both InactiveTrack2MultiMap and
9399  LocationNameMultiMap.
9400 */
9401  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInInactiveTrackAndNameMaps," + AnsiString(VecPos));
9402  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
9403  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9404 
9405  if(!InactiveTrack2MultiMap.empty())
9406  {
9407  for(InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.begin(); InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end();
9408  InactiveTrack2MultiMapIterator++)
9409  {
9410  if(InactiveTrack2MultiMapIterator->second > VecPos)
9411  {
9412  InactiveTrack2MultiMapIterator->second--;
9413  }
9414  // can't be == VecPos as that position erased
9415  }
9416  }
9417  if(!LocationNameMultiMap.empty())
9418  {
9419  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9420  LocationNameMultiMapIterator++)
9421  {
9422  if(LocationNameMultiMapIterator->second < 0)
9423  {
9424  continue; // deal with TrackVectors separately
9425  }
9426  if(LocationNameMultiMapIterator->second > (int)VecPos)
9427  {
9428  LocationNameMultiMapIterator->second--;
9429  }
9430  }
9431  }
9432  Utilities->CallLogPop(593);
9433 }
9434 
9435 // ---------------------------------------------------------------------------
9436 
9437 void TTrack::DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
9438 {
9439 /*
9440  After an element has been erased from the track vector, all the later elements are moved down one. This function
9441  decrements the position values for all values above that of the erased element in the gap elements, TrackMap and
9442  LocationNameMultiMap.
9443 */
9444  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInGapsAndTrackAndNameMaps," + AnsiString(VecPos));
9445  TTrackMapIterator TrackMapIterator;
9446  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9447 
9448  if(!TrackMap.empty())
9449  {
9450  for(TrackMapIterator = TrackMap.begin(); TrackMapIterator != TrackMap.end(); TrackMapIterator++)
9451  {
9452  if(TrackMapIterator->second > VecPos)
9453  {
9454  TrackMapIterator->second--;
9455  }
9456  // can't be == VecPos as that position erased
9457  }
9458  }
9459  if(!LocationNameMultiMap.empty())
9460  {
9461  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9462  LocationNameMultiMapIterator++)
9463  {
9464  if(LocationNameMultiMapIterator->second >= 0)
9465  {
9466  continue; // deal with InactiveTrackVectors separately
9467  }
9468  // (-1-VecPos) VP 0 1 2 3 4 5 6 7
9469  // Val -1 -2 -3 -4 -5 -6 -7 -8
9470  if(LocationNameMultiMapIterator->second < -(int)(VecPos + 1))
9471  {
9472  LocationNameMultiMapIterator->second++;
9473  }
9474  }
9475  }
9476  for(unsigned int x = 0; x < TrackVector.size(); x++)
9477  {
9478  TTrackElement &TkEl = TrackElementAt(1375, x); // no need to check so use this to speed up
9479  if(TkEl.TrackType == GapJump)
9480  {
9481  // position 0 is the gap
9482  if(TkEl.Conn[0] == int(VecPos))
9483  {
9484  TkEl.Conn[0] = -1; // connected to a deleted gap
9485  continue;
9486  }
9487  if(TkEl.Conn[0] > int(VecPos))
9488  {
9489  TkEl.Conn[0]--;
9490  }
9491  if(TkEl.Conn[0] > -1) // don't use 'else' here, need to check the value whether changed or not
9492  {
9493  if(TrackElementAt(709, TkEl.Conn[0]).TrackType != GapJump)
9494  {
9495  TkEl.Conn[0] = -1;
9496  }
9497  }
9498  }
9499  }
9500  Utilities->CallLogPop(1433);
9501 }
9502 
9503 // ---------------------------------------------------------------------------
9504 
9506 /*
9507  Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector. Called after the
9508  track is linked as many of the vector positions are likely to change - called from RepositionAndMapTrack();
9509  after names are changed in EraseLocationAndActiveTrackElementNames; and after the name changes in EnterLocationName.
9510 */
9511 {
9512  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildLocationNameMultiMap");
9513  LocationNameMultiMap.clear();
9514  TLocationNameMultiMapEntry LocationNameEntry;
9515  TTrackElement TrackElement;
9516 
9517  for(unsigned int TVPos = 0; TVPos < TrackVector.size(); TVPos++)
9518  {
9519  TrackElement = TrackElementAt(1376, TVPos);
9520  if(TrackElement.FixedNamedLocationElement)
9521  {
9522  LocationNameEntry.first = TrackElement.LocationName;
9523  LocationNameEntry.second = -1 - TVPos; // adjusted for footcrossings
9524  LocationNameMultiMap.insert(LocationNameEntry);
9525  }
9526  }
9527 
9528  for(unsigned int ITVPos = 0; ITVPos < InactiveTrackVector.size(); ITVPos++)
9529  {
9530  TrackElement = InactiveTrackElementAt(149, ITVPos);
9531  if(TrackElement.FixedNamedLocationElement)
9532  {
9533  LocationNameEntry.first = TrackElement.LocationName;
9534  LocationNameEntry.second = ITVPos;
9535  LocationNameMultiMap.insert(LocationNameEntry);
9536  }
9537  }
9538  Utilities->CallLogPop(594);
9539 }
9540 
9541 // ---------------------------------------------------------------------------
9542 
9544 // Return true if there is a named location present in the railway
9545 // ignores lone footcrossings, can't name these on their own & track won't link if there are any
9546 {
9547  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NonFootCrossingNamedLocationExists");
9548  TTrackVectorIterator ITVI;
9549 
9550  if(InactiveTrackVector.empty())
9551  {
9552  Utilities->CallLogPop(1343);
9553  return(false);
9554  }
9555  for(ITVI = InactiveTrackVector.begin(); ITVI != InactiveTrackVector.end(); ITVI++)
9556  {
9557  if((ITVI->TrackType == Platform) || (ITVI->TrackType == NamedNonStationLocation) || (ITVI->TrackType == Concourse))
9558  {
9559  Utilities->CallLogPop(1404);
9560  return(true);
9561  }
9562  }
9563  Utilities->CallLogPop(1344);
9564  return(false);
9565 }
9566 
9567 // ---------------------------------------------------------------------------
9568 
9570 /*
9571  Work through all elements in TrackVector setting all lengths & speed limits to default values - including both tracks for 2-track elements
9572 */
9573 {
9574  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllDefaultLengthsAndSpeedLimits");
9575 // ResetDistanceElements(6);
9576  for(unsigned int x = 0; x < TrackVector.size(); x++)
9577  {
9578  TTrackElement &TE = TrackElementAt(718, x);
9581  if((TE.TrackType == Points) || (TE.TrackType == Crossover) || (TE.TrackType == Bridge))
9582  {
9585  }
9586  }
9587 /* old function
9588  if((TrackElementAt(, x).TrackType == Points) || (TrackElementAt(, x).TrackType == Crossover) || (TrackElementAt(, x).TrackType == Bridge))
9589  {
9590  SetOneDefaultTrackLength(2, TrackElementAt(, x), 0);
9591  SetOneDefaultTrackLength(3, TrackElementAt(, x), 2);
9592  }
9593  else
9594  {
9595  SetOneDefaultTrackLength(4, TrackElementAt(, x), 0);
9596  }
9597  }
9598 */
9599  Utilities->CallLogPop(617);
9600 }
9601 
9602 // ---------------------------------------------------------------------------
9603 
9604 void TTrack::LengthMarker(int Caller, TDisplay *Disp)
9605 // Examine all elements in the TrackVector and if have a valid length mark the relevant track using MarkOneLength.
9606 {
9607  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LengthMarker");
9608  for(unsigned int x = 0; x < TrackVector.size(); x++)
9609  {
9610  TTrackElement TempElement = TrackElementAt(1377, x);
9611  if(TempElement.Length01 > -1)
9612  {
9613  MarkOneLength(1, TempElement, true, Disp); // need Length01 test in case there are erase elements (but shouldn't be after LinkTrack)
9614  }
9615  if(TempElement.Length23 > -1)
9616  {
9617  MarkOneLength(2, TempElement, false, Disp);
9618  }
9619  }
9620  Disp->Update();
9621  Utilities->CallLogPop(618);
9622 }
9623 
9624 // ---------------------------------------------------------------------------
9625 
9626 void TTrack::MarkOneLength(int Caller, TTrackElement TrackElement, bool FirstTrack, TDisplay *Disp)
9627 /*
9628  Rule: Only marked if different in any way from the default values - length 100m and speed limit 200km/h normally but can be changed in Config.txt
9629  First check using IsElementTrackDefaultLength whether the relevant track is already set to the default values, and if so
9630  return as nothing further to do. Otherwise pick up the appropriate bitmap (using the AutoSigRouteGraphicsPtr bitmaps)
9631  using the same technique as in TPrefDirElement::EntryExitNumber() & *TPrefDirElement::GetPrefDirGraphicPtr(), for the relevant
9632  track as indicated by FirstTrack (true for track01 & false for track23).
9633 */
9634 {
9635  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkOneLength," + TrackElement.LogTrack(8) + "," +
9636  AnsiString((short)FirstTrack));
9637  bool LengthDifferent = false, SpeedDifferent = false;
9638 
9639  if(IsElementDefaultLength(1, TrackElement, FirstTrack, LengthDifferent, SpeedDifferent))
9640  {
9641  Utilities->CallLogPop(619);
9642  return;
9643  }
9644  int EXArray[16][2] =
9645  {{4, 6}, {2, 8}, // horizontal & vertical
9646  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
9647  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
9648  {1, 9}, {3, 7}}; // forward & reverse diagonals
9649 
9650  int Index = -1, BrNum = -1, GrNum = -1, InLink, OutLink;
9651  Graphics::TBitmap *Bitmap;
9652 
9653  if(FirstTrack)
9654  {
9655  InLink = TrackElement.Link[0];
9656  OutLink = TrackElement.Link[1];
9657  }
9658  else
9659  {
9660  InLink = TrackElement.Link[2];
9661  OutLink = TrackElement.Link[3];
9662  }
9663  for(int x = 0; x < 16; x++)
9664  {
9665  if((InLink == EXArray[x][0] && OutLink == EXArray[x][1]) || (InLink == EXArray[x][1] && OutLink == EXArray[x][0]))
9666  {
9667  Index = x;
9668  }
9669  }
9670  if(Index == -1)
9671  {
9672  throw Exception("Error, failed to find Index in TTrack::MarkOneLength");
9673  }
9674 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
9675  the graphic for each of which is different because of the shape of the overbridge. The basic
9676  entry/exit value is computed above, and this used to select only from elements with that entry/exit
9677  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
9678  int BrEXArray[24][2] = {
9679  {4,6},{2,8},{1,9},{3,7},
9680  {1,9},{3,7},{1,9},{3,7},
9681  {2,8},{4,6},{2,8},{4,6}
9682 */
9683  if(!FirstTrack && (TrackElement.TrackType == Bridge))
9684  {
9685  if(Index == 1)
9686  {
9687  if(TrackElement.SpeedTag == 49)
9688  {
9689  BrNum = 1 + 16;
9690  }
9691  else if(TrackElement.SpeedTag == 54)
9692  {
9693  BrNum = 8 + 16;
9694  }
9695  else if(TrackElement.SpeedTag == 55)
9696  {
9697  BrNum = 10 + 16;
9698  }
9699  }
9700  else if(Index == 0)
9701  {
9702  if(TrackElement.SpeedTag == 48)
9703  {
9704  BrNum = 0 + 16;
9705  }
9706  else if(TrackElement.SpeedTag == 58)
9707  {
9708  BrNum = 11 + 16;
9709  }
9710  else if(TrackElement.SpeedTag == 59)
9711  {
9712  BrNum = 9 + 16;
9713  }
9714  }
9715  else if(Index == 14)
9716  {
9717  if(TrackElement.SpeedTag == 50)
9718  {
9719  BrNum = 2 + 16;
9720  }
9721  else if(TrackElement.SpeedTag == 52)
9722  {
9723  BrNum = 4 + 16;
9724  }
9725  else if(TrackElement.SpeedTag == 57)
9726  {
9727  BrNum = 6 + 16;
9728  }
9729  }
9730  else if(Index == 15)
9731  {
9732  if(TrackElement.SpeedTag == 51)
9733  {
9734  BrNum = 3 + 16;
9735  }
9736  else if(TrackElement.SpeedTag == 53)
9737  {
9738  BrNum = 7 + 16;
9739  }
9740  else if(TrackElement.SpeedTag == 56)
9741  {
9742  BrNum = 5 + 16;
9743  }
9744  }
9745  }
9746  if(!FirstTrack && (TrackElement.TrackType == Bridge))
9747  {
9748  GrNum = BrNum;
9749  }
9750  else
9751  {
9752  GrNum = Index;
9753  }
9754  if(LengthDifferent && SpeedDifferent) // blue - use autosig graphics
9755  {
9756  if(GrNum > 15) // underbridge
9757  {
9758  Bitmap = RailGraphics->BridgeRouteAutoSigsGraphicsPtr[GrNum - 16];
9759  }
9760  else
9761  {
9762  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[GrNum];
9763  }
9764  if(TrackElement.SpeedTag == 64)
9765  {
9766  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9767  }
9768  if(TrackElement.SpeedTag == 65)
9769  {
9771  }
9772  if(TrackElement.SpeedTag == 66)
9773  {
9775  }
9776  if(TrackElement.SpeedTag == 67)
9777  {
9779  }
9780  if(TrackElement.SpeedTag == 80)
9781  {
9782  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations to show the dots
9783  }
9784  if(TrackElement.SpeedTag == 81)
9785  {
9787  }
9788  if(TrackElement.SpeedTag == 82)
9789  {
9791  }
9792  if(TrackElement.SpeedTag == 83)
9793  {
9795  }
9796  if(TrackElement.SpeedTag == 84)
9797  {
9799  }
9800  if(TrackElement.SpeedTag == 85)
9801  {
9803  }
9804  if(TrackElement.SpeedTag == 86)
9805  {
9807  }
9808  if(TrackElement.SpeedTag == 87)
9809  {
9811  }
9812  if(TrackElement.SpeedTag == 129)
9813  {
9814  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
9815  }
9816  if(TrackElement.SpeedTag == 130)
9817  {
9819  }
9820  }
9821 
9822  else if(LengthDifferent && !SpeedDifferent) // green - use pref sig graphics
9823  {
9824  if(GrNum > 15) // underbridge
9825  {
9826  Bitmap = RailGraphics->BridgeSigRouteGraphicsPtr[GrNum - 16];
9827  }
9828  else
9829  {
9830  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[GrNum];
9831  }
9832  if(TrackElement.SpeedTag == 64)
9833  {
9834  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9835  }
9836  if(TrackElement.SpeedTag == 65)
9837  {
9838  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[17];
9839  }
9840  if(TrackElement.SpeedTag == 66)
9841  {
9842  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[18];
9843  }
9844  if(TrackElement.SpeedTag == 67)
9845  {
9846  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[19];
9847  }
9848  if(TrackElement.SpeedTag == 80)
9849  {
9850  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
9851  }
9852  if(TrackElement.SpeedTag == 81)
9853  {
9854  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[21];
9855  }
9856  if(TrackElement.SpeedTag == 82)
9857  {
9858  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[22];
9859  }
9860  if(TrackElement.SpeedTag == 83)
9861  {
9862  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[23];
9863  }
9864  if(TrackElement.SpeedTag == 84)
9865  {
9866  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[24];
9867  }
9868  if(TrackElement.SpeedTag == 85)
9869  {
9870  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[25];
9871  }
9872  if(TrackElement.SpeedTag == 86)
9873  {
9874  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[26];
9875  }
9876  if(TrackElement.SpeedTag == 87)
9877  {
9878  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[27];
9879  }
9880  if(TrackElement.SpeedTag == 129)
9881  {
9882  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[28]; // intercept under footbridges
9883  }
9884  if(TrackElement.SpeedTag == 130)
9885  {
9886  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[29];
9887  }
9888  }
9889 
9890  else // SpeedDifferent only: red - use non sig graphics
9891  {
9892  if(GrNum > 15) // underbridge
9893  {
9894  Bitmap = RailGraphics->BridgeNonSigRouteGraphicsPtr[GrNum - 16];
9895  }
9896  else
9897  {
9898  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[GrNum];
9899  }
9900  if(TrackElement.SpeedTag == 64)
9901  {
9902  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9903  }
9904  if(TrackElement.SpeedTag == 65)
9905  {
9907  }
9908  if(TrackElement.SpeedTag == 66)
9909  {
9911  }
9912  if(TrackElement.SpeedTag == 67)
9913  {
9915  }
9916  if(TrackElement.SpeedTag == 80)
9917  {
9918  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
9919  }
9920  if(TrackElement.SpeedTag == 81)
9921  {
9923  }
9924  if(TrackElement.SpeedTag == 82)
9925  {
9927  }
9928  if(TrackElement.SpeedTag == 83)
9929  {
9931  }
9932  if(TrackElement.SpeedTag == 84)
9933  {
9935  }
9936  if(TrackElement.SpeedTag == 85)
9937  {
9939  }
9940  if(TrackElement.SpeedTag == 86)
9941  {
9943  }
9944  if(TrackElement.SpeedTag == 87)
9945  {
9947  }
9948  if(TrackElement.SpeedTag == 129)
9949  {
9950  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[28]; // intercept under footbridges
9951  }
9952  if(TrackElement.SpeedTag == 130)
9953  {
9955  }
9956  }
9957  Disp->PlotOutput(67, TrackElement.HLoc * 16, TrackElement.VLoc * 16, Bitmap);
9958  Utilities->CallLogPop(620);
9959 }
9960 
9961 // ---------------------------------------------------------------------------
9962 
9963 bool TTrack::IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
9964 /* FirstTrack = LinkPos's 0 & 1
9965  Examine track within TrackElement & check whether it has the default length and speed limit, return true if so
9966 */
9967 {
9968  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementTrackDefaultLength," + TrackElement.LogTrack(10) + "," +
9969  AnsiString((short)FirstTrack));
9970  LengthDifferent = false;
9971  SpeedDifferent = false;
9972  if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && FirstTrack)
9973  {
9974  if(TrackElement.Length01 != DefaultTrackLength)
9975  {
9976  LengthDifferent = true;
9977  }
9978  if(TrackElement.SpeedLimit01 != DefaultTrackSpeedLimit)
9979  {
9980  SpeedDifferent = true;
9981  }
9982  if(LengthDifferent || SpeedDifferent)
9983  {
9984  Utilities->CallLogPop(625);
9985  return(false);
9986  }
9987  Utilities->CallLogPop(626);
9988  return(true);
9989  }
9990 
9991  else if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && !FirstTrack)
9992  {
9993  if(TrackElement.Length23 != DefaultTrackLength)
9994  {
9995  LengthDifferent = true;
9996  }
9997  if(TrackElement.SpeedLimit23 != DefaultTrackSpeedLimit)
9998  {
9999  SpeedDifferent = true;
10000  }
10001  if(LengthDifferent || SpeedDifferent)
10002  {
10003  Utilities->CallLogPop(627);
10004  return(false);
10005  }
10006  Utilities->CallLogPop(628);
10007  return(true);
10008  }
10009 
10010  else // any other 1 track element, including platforms being present
10011  {
10012  if(TrackElement.Length01 != DefaultTrackLength)
10013  {
10014  LengthDifferent = true;
10015  }
10016  if(TrackElement.SpeedLimit01 != DefaultTrackSpeedLimit)
10017  {
10018  SpeedDifferent = true;
10019  }
10020  if(LengthDifferent || SpeedDifferent)
10021  {
10022  Utilities->CallLogPop(629);
10023  return(false);
10024  }
10025  Utilities->CallLogPop(630);
10026  return(true);
10027  }
10028 }
10029 
10030 // ---------------------------------------------------------------------------
10031 
10032 bool TTrack::IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
10033 // Check whether there is a platform or NamedNonStationLocation present at HLoc & VLoc, return true if so
10034 {
10035  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPlatformOrNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
10036  AnsiString(VLoc));
10037  bool FoundFlag;
10038  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(11, HLoc, VLoc, FoundFlag);
10039 
10040  if(!FoundFlag)
10041  {
10042  Utilities->CallLogPop(633);
10043  return(false);
10044  }
10045  if((InactiveTrackElementAt(42, IMPair.first).TrackType == Platform) || (InactiveTrackElementAt(91, IMPair.first).TrackType == NamedNonStationLocation))
10046  {
10047  Utilities->CallLogPop(634);
10048  return(true); // only need to check first since if second is a platform the the first must be too
10049  }
10050  else
10051  {
10052  Utilities->CallLogPop(635);
10053  return(false);
10054  }
10055 }
10056 
10057 // ---------------------------------------------------------------------------
10058 
10059 bool TTrack::IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
10060 // Check whether there is a NamedNonStationLocation present at HLoc & VLoc, return true if so
10061 {
10062  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
10063  AnsiString(VLoc));
10064  bool FoundFlag;
10065  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(12, HLoc, VLoc, FoundFlag);
10066 
10067  if(!FoundFlag)
10068  {
10069  Utilities->CallLogPop(636);
10070  return(false);
10071  }
10073  {
10074  Utilities->CallLogPop(637);
10075  return(true); // only need to check first since only one used for NamedNonStationLocations
10076  }
10077  else
10078  {
10079  Utilities->CallLogPop(638);
10080  return(false);
10081  }
10082 }
10083 
10084 // ---------------------------------------------------------------------------
10085 
10087 /* Called when trying to link track and when a name changed when track already linked. Examines all track elements that
10088  have ActiveTrackElementName set, sums the number of consecutive elements with the same name, and sets the EntryLink values for
10089  the front of train stop points for each direction.
10090  For stations (not non-station named locations) of length n, where n > 1, stop element is [floor((n+1)/2) + 1] from each
10091  end (unless buffers at one or both ends in which case stop points are the end elements).
10092  Note that for a single element the stop point is the element itself (formula doesn't apply).
10093  During the function the StationEntryStopLink values are set to 5 if not used, so no need to keep
10094  repeating the procedure for every element. At the end all unused values are returned to -1.
10095  For NamedNonStationLocations the stop points are at the end elements to allow trains to stack up.
10096 */
10097 {
10098  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetStationEntryStopLinkPosses");
10099  TTrackElement TempElement, StartElement;
10100  AnsiString TempName;
10101  int VecPos, StartVecPos, Count, EntryPos, StartEntryPos, ForwardNumber, ReverseNumber;
10102  bool ForwardSet, ReverseSet;
10103 
10104  for(unsigned int x = 0; x < TrackVector.size(); x++)
10105  {
10108  }
10109  for(unsigned int x = 0; x < TrackVector.size(); x++)
10110  {
10111  ForwardSet = false;
10112  ReverseSet = false;
10113  TempElement = TrackElementAt(1380, x);
10114  VecPos = x;
10115  if((TempElement.ActiveTrackElementName != "") && (TempElement.StationEntryStopLinkPos1 == -1))
10116  // 2nd condition incl so don't re-examine elements with stop links set to 5
10117  {
10118  TempName = TempElement.ActiveTrackElementName;
10119  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(44, TempElement.Conn[0]).ActiveTrackElementName == TempName) &&
10120  (TrackElementAt(45, TempElement.Conn[1]).ActiveTrackElementName == TempName))
10121  // an element linked at both ends where both links are also named elements
10122  // only Conn[0] & [1] relevant for ActiveTrackElementName elements (only 2-track named element is points, and only straight track relevant & this has 0 & 1 as entry/exit positions)
10123  {
10124  continue; // looking for an end element so skip this one
10125  }
10126  else // reached one end
10127  {
10128  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(46, TempElement.Conn[0]).ActiveTrackElementName != TempName) &&
10129  (TrackElementAt(47, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10130  // single named element linked at both ends
10131  {
10132  TrackElementAt(48, VecPos).StationEntryStopLinkPos1 = 0;
10133  TrackElementAt(49, VecPos).StationEntryStopLinkPos2 = 1;
10134  continue;
10135  }
10136  else if((TempElement.TrackType == Buffers) && (TrackElementAt(618, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10137  // single named buffer element (LinkPos 1 is the non-buffer end)
10138  {
10139  TrackElementAt(619, VecPos).StationEntryStopLinkPos1 = 0;
10140  TrackElementAt(620, VecPos).StationEntryStopLinkPos2 = 1;
10141  continue;
10142  }
10143  else
10144  // Note: only interested in connection positions 0 & 1 since all named elements are single track except points,
10145  // and platforms always on straight (conns 0 & 1) section of points
10146  {
10147  for(int y = 0; y < 2; y++)
10148  {
10149  int Dir = y; // Dir is the ExitPos of the element, towards the rest of the named elements
10150  // check for buffers at both ends - no need, function below now covers buffers at one & both ends
10151 /* TTrackElement Temp1 = TempElement;
10152  ***********New section, compiles but not checked - does bit below need to be else if?
10153  if((Temp1.TrackType == Buffers) && (Temp1.GetConfig(Dir) != End))
10154  {
10155  //search along Dir direction until find other end, skip if Dir facing buffer end
10156  int NewDir = Dir;
10157  int NewVecPos;
10158  while((Temp1.Conn[NewDir] > -1) && (TrackElementAt(598, Temp1.Conn[NewDir]).ActiveTrackElementName == TempName))
10159  {
10160  NewVecPos = Temp1.Conn[NewDir];
10161  NewDir = Track->GetNonPointsOppositeLinkPos(Temp1.ConnLinkPos[NewDir]);
10162  Temp1 = TrackElementAt(601, NewVecPos);
10163  }
10164  if((Temp1.Conn[NewDir] == -1) && (Temp1.TrackType == Buffers))
10165  {
10166  TrackElementAt(599, VecPos).StationEntryStopLinkPos1 = Dir;//EntryPos for train coming from other end is Dir
10167  TrackElementAt(600, NewVecPos).StationEntryStopLinkPos2 = 1 - NewDir;//For train moving in same direction as search direction its EntryPos == 1 - NewDir since NewDir is the ExitPos
10168  }
10169  }
10170  ***************
10171 */
10172  // end may be linked at both ends but only one link named, or buffer with linked element named
10173  // if a buffer then the named linkpos has to be 1
10174  // already dealt with all types of single element so at least 2 linked named element
10175  if(((TempElement.Conn[Dir] > -1) && (TempElement.Conn[1 - Dir] > -1) && (TrackElementAt(50,
10176  TempElement.Conn[1 - Dir]).ActiveTrackElementName != TempName)) || ((TempElement.TrackType == Buffers) && (Dir == 1)))
10177  {
10178  StartElement = TempElement;
10179  StartVecPos = VecPos;
10180  TrackElementAt(51, VecPos).StationEntryStopLinkPos1 = 5; // set to 5 to stop re-examination in later searches, all set back at end
10181  TrackElementAt(52, VecPos).StationEntryStopLinkPos2 = 5;
10182  EntryPos = 1 - Dir;
10183  StartEntryPos = 1 - Dir;
10184  Count = 1;
10185  // work along named elements until find the other end
10186  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(53,
10187  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName))
10188  // at end of 'while' Count = length (in elements) of platform/nonstationloc, VecPos = vector number of far end
10189  // which is the last named element that is track-linked to the rest of the location, it may be a buffer
10190  // all stop link pos's are set to 5
10191  {
10192  VecPos = TempElement.Conn[1 - EntryPos];
10193  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
10194  TempElement = TrackElementAt(54, TempElement.Conn[1 - EntryPos]);
10195  EntryPos = TempEntryPos;
10196  Count++;
10197  TrackElementAt(55, VecPos).StationEntryStopLinkPos1 = 5;
10198  TrackElementAt(56, VecPos).StationEntryStopLinkPos2 = 5;
10199  }
10200  // here when reached other end, maybe buffers, continuation or last named linked element
10201  if(TrackElementAt(57, VecPos).TrackType == Buffers)
10202  // terminal station, set end elements as stop elements
10203  {
10204  TrackElementAt(58, VecPos).StationEntryStopLinkPos1 = EntryPos;
10205  TrackElementAt(59, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos; // for train leaving
10206  continue;
10207  }
10208  if(TrackElementAt(60, StartVecPos).TrackType == Buffers) // best not to use 'else if' as both ends could be buffers!
10209  // terminal station, set end elements as stop elements
10210  {
10211  TrackElementAt(61, VecPos).StationEntryStopLinkPos1 = EntryPos;
10212  TrackElementAt(62, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
10213  continue;
10214  }
10215  if(IsNamedNonStationLocationPresent(1, TrackElementAt(63, StartVecPos).HLoc, TrackElementAt(64, StartVecPos).VLoc))
10216  // NonStationLocation so set end elements as stop elements
10217  {
10218  TrackElementAt(65, VecPos).StationEntryStopLinkPos1 = EntryPos;
10219  TrackElementAt(66, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
10220  continue;
10221  }
10222  // now Count == length of platform, can calculate StationEntryStopLinkPos values and the elements to which they apply
10223  ForwardNumber = ((Count + 1) / 2) + 1;
10224  ReverseNumber = (Count - ForwardNumber) + 1;
10225  Count = 1; // starting value
10226  EntryPos = 1 - Dir;
10227  TempElement = StartElement;
10228  VecPos = StartVecPos;
10229  if(Count == ForwardNumber)
10230  {
10231  TrackElementAt(67, VecPos).StationEntryStopLinkPos1 = EntryPos;
10232  ForwardSet = true;
10233  }
10234  if(Count == ReverseNumber) // don't use 'else' as may both be at same element
10235  {
10236  TrackElementAt(68, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10237  ReverseSet = true;
10238  }
10239  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(69,
10240  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName) && (!ForwardSet || !ReverseSet))
10241  {
10242  VecPos = TempElement.Conn[1 - EntryPos];
10243  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
10244  TempElement = TrackElementAt(70, TempElement.Conn[1 - EntryPos]);
10245  EntryPos = TempEntryPos;
10246  Count++;
10247  if(Count == ForwardNumber)
10248  {
10249  TrackElementAt(71, VecPos).StationEntryStopLinkPos1 = EntryPos;
10250  ForwardSet = true;
10251  }
10252  if(Count == ReverseNumber)
10253  {
10254  TrackElementAt(72, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10255  ReverseSet = true;
10256  }
10257  }
10258  }
10259  }
10260  }
10261  }
10262  }
10263  }
10264  for(unsigned int x = 0; x < TrackVector.size(); x++)
10265  {
10266  if(TrackElementAt(1381, x).StationEntryStopLinkPos1 == 5)
10267  {
10269  }
10270  if(TrackElementAt(1383, x).StationEntryStopLinkPos2 == 5)
10271  {
10273  }
10274  }
10275  Utilities->CallLogPop(639);
10276 }
10277 
10278 // ---------------------------------------------------------------------------
10279 
10280 void TTrack::PlotSmallRailway(int Caller, TDisplay *Disp)
10281 {
10282  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRailway");
10283  TTrackElement Next;
10284 
10286  while(ReturnNextInactiveTrackElement(1, Next))
10287  {
10288  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10289  {
10290  if(((Next.TrackType == Platform) || (Next.TrackType == Concourse) || (Next.TrackType == NamedNonStationLocation)) && (Next.LocationName == ""))
10291  // need striped graphics
10292  {
10293  if(Next.SpeedTag == 76)
10294  {
10295  Disp->PlotSmallOutput(11, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm76striped);
10296  }
10297  else if(Next.SpeedTag == 77)
10298  {
10299  Disp->PlotSmallOutput(12, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm77striped);
10300  }
10301  else if(Next.SpeedTag == 78)
10302  {
10303  Disp->PlotSmallOutput(13, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm78striped);
10304  }
10305  else if(Next.SpeedTag == 79)
10306  {
10307  Disp->PlotSmallOutput(14, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm79striped);
10308  }
10309  else if(Next.SpeedTag == 96)
10310  {
10311  Disp->PlotSmallOutput(15, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm96striped);
10312  }
10313  else if(Next.SpeedTag == 131)
10314  {
10315  Disp->PlotSmallOutput(16, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm131striped);
10316  }
10317  }
10318  else
10319  {
10320  Disp->PlotSmallOutput(17, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10321  }
10322  }
10323  }
10324 
10325  NextTrackElementPtr = TrackVector.begin();
10326  while(ReturnNextTrackElement(1, Next))
10327  {
10328  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10329  {
10330  if((Next.TrackType == FootCrossing) && (Next.LocationName == "")) // need striped graphics, use sm129 & 130 for 145 & 146
10331  {
10332  if((Next.SpeedTag == 129) || (Next.SpeedTag == 145))
10333  {
10334  Disp->PlotSmallOutput(18, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm129striped);
10335  }
10336  else if((Next.SpeedTag == 130) || (Next.SpeedTag == 146))
10337  {
10338  Disp->PlotSmallOutput(19, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm130striped);
10339  }
10340  }
10341  else
10342  {
10343  Disp->PlotSmallOutput(20, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10344  }
10345  }
10346  }
10347  Disp->Update();
10348  Utilities->CallLogPop(640);
10349 }
10350 
10351 // ---------------------------------------------------------------------------
10352 
10353 void TTrack::PlotSmallRedGap(int Caller)
10354 {
10355  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRedGap");
10357  Utilities->CallLogPop(1346);
10358 }
10359 
10360 // ---------------------------------------------------------------------------
10361 
10362 void TTrack::TrackClear(int Caller)
10363 {
10364  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackClear");
10365  TrackVector.clear();
10366  InactiveTrackVector.clear();
10367  TrackMap.clear();
10369  if(TextHandler->TextVector.size() == 0)
10370  {
10371  Display->DisplayOffsetH = 0;
10372  Display->DisplayOffsetV = 0;
10379  HLocMin = 2000000000;
10380  HLocMax = -2000000000;
10381  VLocMin = 2000000000;
10382  VLocMax = -2000000000;
10383  }
10384  else
10385  {
10386  CalcHLocMinEtc(4);
10387  }
10388  Utilities->CallLogPop(1347);
10389 }
10390 
10391 // ---------------------------------------------------------------------------
10392 
10393 void TTrack::CalcHLocMinEtc(int Caller)
10394 {
10395  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcHLocMinEtc");
10396  HLocMin = 2000000000;
10397  VLocMin = 2000000000;
10398  HLocMax = -2000000000;
10399  VLocMax = -2000000000;
10400  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
10401  {
10402  if(TrackElementAt(1385, x).SpeedTag == 0)
10403  {
10404  continue; // skip erase elements or would interfere with Min & Max values
10405  }
10406  if(TrackElementAt(1386, x).HLoc - 1 < HLocMin)
10407  {
10408  HLocMin = TrackElementAt(1387, x).HLoc - 1; // add one all round
10409  }
10410  if(TrackElementAt(1388, x).HLoc + 1 > HLocMax)
10411  {
10412  HLocMax = TrackElementAt(1389, x).HLoc + 1;
10413  }
10414  if(TrackElementAt(1390, x).VLoc - 1 < VLocMin)
10415  {
10416  VLocMin = TrackElementAt(1391, x).VLoc - 1;
10417  }
10418  if(TrackElementAt(1392, x).VLoc + 1 > VLocMax)
10419  {
10420  VLocMax = TrackElementAt(1393, x).VLoc + 1;
10421  }
10422  }
10423  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++) // check all elements in turn
10424  {
10425  if(InactiveTrackElementAt(150, x).SpeedTag == 0)
10426  {
10427  continue; // shouldn't be any inactive erase elements but include anyway
10428  }
10429  if(InactiveTrackElementAt(151, x).HLoc - 1 < HLocMin)
10430  {
10431  HLocMin = InactiveTrackElementAt(152, x).HLoc - 1; // add one all round
10432  }
10433  if(InactiveTrackElementAt(153, x).HLoc + 1 > HLocMax)
10434  {
10435  HLocMax = InactiveTrackElementAt(162, x).HLoc + 1;
10436  }
10437  if(InactiveTrackElementAt(154, x).VLoc - 1 < VLocMin)
10438  {
10439  VLocMin = InactiveTrackElementAt(155, x).VLoc - 1;
10440  }
10441  if(InactiveTrackElementAt(156, x).VLoc + 1 > VLocMax)
10442  {
10443  VLocMax = InactiveTrackElementAt(157, x).VLoc + 1;
10444  }
10445  }
10446  for(unsigned int x = 0; x < TextHandler->TextVectorSize(10); x++) // check all elements in turn
10447  {
10448 /* Removed at v2.2.0: It isn't needed because null names aren't entered into vector, and in any case if were then
10449  will fail as x will exceed the maximum value
10450  if(TextHandler->TextPtrAt(, x)->TextString == "")
10451  {
10452  TextHandler->TextErase(, TextHandler->TextPtrAt(35, x)->HPos, TextHandler->TextPtrAt(36, x)->VPos);
10453  }
10454 */
10455  int TextH = TextHandler->TextPtrAt(0, x)->HPos, TextV = TextHandler->TextPtrAt(1, x)->VPos;
10456  if((TextH / 16) - 1 < HLocMin)
10457  {
10458  HLocMin = (TextH / 16) - 1; // integer division will truncate so subtract 1 to ensure include the start
10459  }
10460  if((TextH / 16) + 1 > HLocMax)
10461  {
10462  HLocMax = (TextH / 16) + 1; // integer division will truncate so add 1 to ensure include the start
10463  }
10464  if((TextV / 16) - 1 < VLocMin)
10465  {
10466  VLocMin = (TextV / 16) - 1;
10467  }
10468  if((TextV / 16) + 1 > VLocMax)
10469  {
10470  VLocMax = (TextV / 16) + 1;
10471  }
10472  }
10473  for(unsigned int x = 0; x < UserGraphicVector.size(); x++) // added at v2.4.0
10474  {
10475  if((UserGraphicVectorAt(5, x).HPos / 16) - 1 < HLocMin)
10476  {
10477  HLocMin = (UserGraphicVectorAt(6, x).HPos / 16) - 1; // add one all round
10478  }
10479  if(((UserGraphicVectorAt(7, x).HPos + UserGraphicVectorAt(8, x).Width) / 16) + 1 > HLocMax)
10480  {
10481  HLocMax = ((UserGraphicVectorAt(9, x).HPos + UserGraphicVectorAt(10, x).Width) / 16) + 1;
10482  }
10483  if((UserGraphicVectorAt(11, x).VPos / 16) - 1 < VLocMin)
10484  {
10485  VLocMin = (UserGraphicVectorAt(12, x).VPos / 16) - 1;
10486  }
10487  if(((UserGraphicVectorAt(13, x).VPos + UserGraphicVectorAt(14, x).Height) / 16) + 1 > VLocMax)
10488  {
10489  VLocMax = ((UserGraphicVectorAt(15, x).VPos + UserGraphicVectorAt(16, x).Height) / 16) + 1;
10490  }
10491  }
10492 
10493  Utilities->CallLogPop(641);
10494 }
10495 
10496 // ---------------------------------------------------------------------------
10497 
10498 void TTrack::UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos,
10499  bool &UserGraphicFoundFlag)
10500 {
10501  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicMove," + AnsiString(HPosInput) + "," + AnsiString(VPosInput));
10502  TUserGraphicVector::iterator UserGraphicPtr;
10503 
10504  UserGraphicFoundFlag = false;
10505  if(!UserGraphicVector.empty())
10506  {
10507  int x = UserGraphicVector.size();
10508  for(UserGraphicPtr = (UserGraphicVector.end() - 1); UserGraphicPtr >= UserGraphicVector.begin(); UserGraphicPtr--)
10509  {
10510  x--;
10511  if((HPosInput >= (*UserGraphicPtr).HPos) && (HPosInput < ((*UserGraphicPtr).HPos + (*UserGraphicPtr).Width)) && (VPosInput >=
10512  (*UserGraphicPtr).VPos) && (VPosInput < ((*UserGraphicPtr).VPos + (*UserGraphicPtr).Height)))
10513  {
10514  UserGraphicItem = x;
10515  UserGraphicMoveHPos = (*UserGraphicPtr).HPos;
10516  UserGraphicMoveVPos = (*UserGraphicPtr).VPos;
10517  UserGraphicFoundFlag = true;
10518  Utilities->CallLogPop(2177);
10519  return;
10520  } // if ....
10521 
10522  } // for UserGraphicPtr...
10523  } // if !UserGraphicVector...
10524 
10525  Utilities->CallLogPop(2197);
10526 }
10527 
10528 // ---------------------------------------------------------------------------
10529 
10531 {
10532  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RetrieveStripedNamedLocationGraphicsWhereRelevant," +
10533  TrackElement.LogTrack(11));
10534  Graphics::TBitmap *GraphicOutput = RailGraphics->bmTransparentBgnd; // default value
10535  int SpeedTag = TrackElement.SpeedTag;
10536 
10537  if(SpeedTag < 1)
10538  {
10539  throw Exception("Error - SpeedTag value " + AnsiString(SpeedTag) + " in RetrieveStripedNamedLocationGraphicsWhereRelevant");
10540  }
10541  switch(SpeedTag)
10542  {
10543  case 76: // t platform
10544  GraphicOutput = RailGraphics->gl76Striped;
10545  break;
10546 
10547  case 77: // h platform
10548  GraphicOutput = RailGraphics->bm77Striped;
10549  break;
10550 
10551  case 78: // v platform
10552  GraphicOutput = RailGraphics->bm78Striped;
10553  break;
10554 
10555  case 79: // r platform
10556  GraphicOutput = RailGraphics->gl79Striped;
10557  break;
10558 
10559  case 96: // concourse
10560  GraphicOutput = RailGraphics->ConcourseStriped;
10561  break;
10562 
10563  case 129: // v footbridge
10564  GraphicOutput = RailGraphics->gl129Striped;
10565  break;
10566 
10567  case 130: // h footbridge
10568  GraphicOutput = RailGraphics->gl130Striped;
10569  break;
10570 
10571  case 131: // non-station named loc
10572  GraphicOutput = RailGraphics->bmNameStriped;
10573  break;
10574 
10575  case 145: // v u'pass
10576  GraphicOutput = RailGraphics->gl145Striped;
10577  break;
10578 
10579  case 146: // h u'pass
10580  GraphicOutput = RailGraphics->gl146Striped;
10581  break;
10582 
10583  default:
10584  GraphicOutput = TrackElement.GraphicPtr;
10585  break;
10586  }
10587  Utilities->CallLogPop(642);
10588  return(GraphicOutput);
10589 }
10590 
10591 // ---------------------------------------------------------------------------
10592 
10594 {
10595  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementAt," + AnsiString(At));
10596  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
10597  {
10598 // Utilities->CallLogPop(2281); this shouldn't be here, introduced 02/06/21 at revision 3745fadb... with no explanation
10599  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in TrackElementAt");
10600  }
10601  Utilities->CallLogPop(643);
10602  return(TrackVector.at(At));
10603 }
10604 
10605 // ---------------------------------------------------------------------------
10606 
10608 {
10609  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementAt," + AnsiString(At));
10610  if((At < 0) || ((unsigned int)At >= InactiveTrackVector.size()))
10611  {
10612  throw Exception("Out of Range Error, vector size: " + AnsiString(InactiveTrackVector.size()) + ", At: " + AnsiString(At) +
10613  " in InactiveTrackElementAt");
10614  }
10615  Utilities->CallLogPop(644);
10616  return(InactiveTrackVector.at(At));
10617 }
10618 
10619 // ---------------------------------------------------------------------------
10620 
10621 bool TTrack::BlankElementAt(int Caller, int At) const
10622 {
10623  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BlankElementAt," + AnsiString(At));
10624  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
10625  {
10626  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in BlankElementAt");
10627  }
10628  if(TrackVector.at(At).SpeedTag == 0) //have to use TrackVector.at because TrackElementAt is non-const
10629  {
10630  Utilities->CallLogPop(645);
10631  return(true);
10632  }
10633  else
10634  {
10635  Utilities->CallLogPop(646);
10636  return(false);
10637  }
10638 }
10639 
10640 // ---------------------------------------------------------------------------
10641 
10642 bool TTrack::OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
10643 /* Check sufficient elements with same ActiveTrackElementName linked together without any trailing point links to allow a train split.
10644  Only one length is needed to return true, but this doesn't mean that all platforms at the location are long enough. When a
10645  split is required a specific check is made using ThisNamedLocationLongEnoughForSplit.
10646  Need at least two linked ActiveTrackElementNames, with connected elements at each end, which may or may not be ActiveTrackElementNames,
10647  and no connections via point trailing links. Note that these conditions exclude opposed buffers since these not linked.
10648 */
10649 {
10650  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationLongEnoughForSplit," + LocationName);
10651  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
10652  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
10653  TLocationNameMultiMapIterator SNIterator;
10654  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10655 
10656  if(SNRange.first == SNRange.second)
10657  {
10658  Utilities->CallLogPop(972);
10659  return(false); // should have been caught earlier but include for completeness
10660  }
10661  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10662  {
10663  if(SNIterator->second < 0)
10664  {
10665  continue; // exclude footcrossings
10666  }
10667  InactiveElement = InactiveTrackElementAt(47, SNIterator->second);
10668  if(InactiveElement.TrackType == Concourse)
10669  {
10670  continue; // only interested in locations where ActiveTrackElementName may be set (not needed at v2.10.0 but leave in)
10671  }
10672  if(!TrackElementPresentAtHV(1, InactiveElement.HLoc, InactiveElement.VLoc)) //added at v2.10.0 in response to Jason Bassett error notified 14/08/21
10673  {
10674  continue; // only interested in locations where ActiveTrackElementName may be set
10675  }
10676  THVPair HVPair;
10677  HVPair.first = InactiveElement.HLoc;
10678  HVPair.second = InactiveElement.VLoc;
10679  if(TrackMap.find(HVPair) == TrackMap.end())
10680  {
10681  throw Exception
10682  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in OneNamedLocationLongEnoughForSplit (1)");
10683  }
10684  int TVPos = TrackMap.find(HVPair)->second;
10685  FirstNamedElement = TrackElementAt(560, TVPos);
10686  // first check linked on both sides, skip the check if not
10687  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
10688  {
10689  continue;
10690  }
10691  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
10692  // ActiveTrackElementNames are points and excluding trailing connections for points
10693  FirstNamedExitPos = 0;
10694  {
10695  SecondNamedElement = TrackElementAt(561, FirstNamedElement.Conn[FirstNamedExitPos]);
10696  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10697  FirstNamedLinkedElement = TrackElementAt(562, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10698  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10699  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10700  {
10701  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10702  {
10703  SecondNamedLinkedElement = TrackElementAt(563, SecondNamedElement.Conn[SecondNamedExitPos]);
10704  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10705  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10706  // success, now check FirstNamedElement link not trailing points & if so all OK
10707  {
10708  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10709  {
10710  Utilities->CallLogPop(1002);
10711  return(true);
10712  }
10713  }
10714  }
10715  }
10716  }
10717  // failed, try link 1
10718  FirstNamedExitPos = 1;
10719  {
10720  SecondNamedElement = TrackElementAt(564, FirstNamedElement.Conn[FirstNamedExitPos]);
10721  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10722  FirstNamedLinkedElement = TrackElementAt(565, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10723  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10724  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10725  {
10726  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10727  {
10728  SecondNamedLinkedElement = TrackElementAt(566, SecondNamedElement.Conn[SecondNamedExitPos]);
10729  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10730  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10731  // success, now check FirstNamedElement link not trailing points & if so all OK
10732  {
10733  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10734  {
10735  Utilities->CallLogPop(1003);
10736  return(true);
10737  }
10738  }
10739  }
10740  }
10741  }
10742  }
10743  Utilities->CallLogPop(1004);
10744  return(false);
10745 }
10746 
10747 // ---------------------------------------------------------------------------
10748 bool TTrack::ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos,
10749  int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
10750 // for success need two linked named location elements, so that one element of each train can be at the location
10751 // FirstNamedElementPos is the input vector position and the first (if successful) of the two linked named location elements,
10752 // the second is SecondNamedElementPos, and the two linked elements are FirstNamedLinkedElementPos and SecondNamedLinkedElementPos.
10753 // the two trains will occupy these 4 elements
10754 // All are track vector positions, all but the input being references and set within the function.
10755 {
10756 /* Check sufficient elements (including TrackvectorPosition) with same ActiveTrackElementName linked together without any trailing point
10757  links and including the element FirstNamedElementPos to allow a train split. Need at least two linked ActiveTrackElementNames, with
10758  connected elements at each end, which may or may not be ActiveTrackElementNames, and no connections via point trailing links. Note that
10759  these conditions exclude opposed buffers since these not linked. Return the two train positions and exit positions for use in train
10760  splitting.
10761 */
10762  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ThisNamedLocationLongEnoughForSplit," + LocationName +
10763  AnsiString(FirstNamedElementPos));
10764  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
10765  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
10766 
10767  SecondNamedElementPos = -1;
10768  FirstNamedLinkedElementPos = -1;
10769  SecondNamedLinkedElementPos = -1;
10770  TLocationNameMultiMapIterator SNIterator;
10771  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10772 
10773  if(SNRange.first == SNRange.second) // i.e. location name not in map
10774  {
10775  Utilities->CallLogPop(1005);
10776  return(false); // should have been caught earlier but include for completeness
10777  }
10778  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10779  {
10780  if(SNIterator->second < 0)
10781  {
10782  continue; // exclude footcrossings
10783  }
10784  InactiveElement = InactiveTrackElementAt(69, SNIterator->second);
10785  if(InactiveElement.TrackType == Concourse)
10786  {
10787  continue; // only interested in locations where ActiveTrackElementName may be set
10788  }
10789  THVPair HVPair;
10790  HVPair.first = InactiveElement.HLoc;
10791  HVPair.second = InactiveElement.VLoc;
10792  if(TrackMap.find(HVPair) == TrackMap.end())
10793  {
10794  if(InactiveElement.TrackType == NamedNonStationLocation) // added at v2.2.0 to correct the error Xeon reported on 14/07/18.
10795  // If there is a NamedNonStationLocation without an associated active track element (effectively a non-station concourse)
10796  // then it won't be found in TrackMap but it's still legitimate.
10797  {
10798  continue;
10799  }
10800  else // for anything else throw the error
10801  {
10802  throw Exception
10803  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in ThisNamedLocationLongEnoughForSplit (2)"
10804  );
10805  }
10806  }
10807  int TVPos = TrackMap.find(HVPair)->second;
10808  if(TVPos != FirstNamedElementPos)
10809  {
10810  continue; // looking for an exact match
10811  }
10812  FirstNamedElement = TrackElementAt(567, TVPos);
10813  // first check linked on both sides, skip the check if not
10814  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
10815  {
10816  continue;
10817  }
10818  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
10819  // ActiveTrackElementNames are points and excluding trailing connections for points
10820  FirstNamedExitPos = 0;
10821  {
10822  SecondNamedElement = TrackElementAt(568, FirstNamedElement.Conn[FirstNamedExitPos]);
10823  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10824  FirstNamedLinkedElement = TrackElementAt(569, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10825  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10826  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10827  {
10828  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10829  {
10830  SecondNamedLinkedElement = TrackElementAt(570, SecondNamedElement.Conn[SecondNamedExitPos]);
10831  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10832  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10833  // success, now check FirstNamedElement link not trailing points & if so all OK
10834  {
10835  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10836  {
10837  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
10838  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
10839  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
10840  Utilities->CallLogPop(1006);
10841  return(true);
10842  }
10843  }
10844  }
10845  }
10846  }
10847  // failed, try link 1
10848  FirstNamedExitPos = 1;
10849  {
10850  SecondNamedElement = TrackElementAt(571, FirstNamedElement.Conn[FirstNamedExitPos]);
10851  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10852  FirstNamedLinkedElement = TrackElementAt(572, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10853  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10854  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10855  {
10856  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10857  {
10858  SecondNamedLinkedElement = TrackElementAt(573, SecondNamedElement.Conn[SecondNamedExitPos]);
10859  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10860  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10861  // success, now check FirstNamedElement link not trailing points & if so all OK
10862  {
10863  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10864  {
10865  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
10866  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
10867  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
10868  Utilities->CallLogPop(1007);
10869  return(true);
10870  }
10871  }
10872  }
10873  }
10874  }
10875  }
10876  Utilities->CallLogPop(1008);
10877  return(false);
10878 }
10879 
10880 // ---------------------------------------------------------------------------
10881 
10882 bool TTrack::OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
10883 {
10884  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationElementAtLocation," + LocationName);
10885  TLocationNameMultiMapIterator SNIterator;
10886  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10887 
10888  if(SNRange.first != SNRange.second)
10889  {
10890  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10891  {
10892  if(SNIterator->second < 0)
10893  {
10894  continue; // only looking for inactive (platform or NamedNonStationLocation) elements
10895  }
10896  if((InactiveTrackElementAt(33, SNIterator->second).TrackType == Platform) || (InactiveTrackElementAt(81,
10897  SNIterator->second).TrackType == NamedNonStationLocation))
10898  {
10899  Utilities->CallLogPop(1121);
10900  return(true);
10901  }
10902  }
10903  }
10904  Utilities->CallLogPop(848);
10905  return(false);
10906 }
10907 
10908 // ---------------------------------------------------------------------------
10909 
10910 bool TTrack::PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap* &SignalPlatformGraphic)
10911 {
10912 // dropped special platforms at v0.6 as didn't show well against ground signals & not needed anyway as plats always plotted first where there are signals
10913  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlatformOnSignalSide," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
10914  "," + AnsiString(SpeedTag));
10915  if(!IsPlatformOrNamedNonStationLocationPresent(5, HLoc, VLoc)) // can't be a named location so no ambiguity
10916  {
10917  Utilities->CallLogPop(949);
10918  return(false);
10919  }
10920  bool FoundFlag;
10921  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(27, HLoc, VLoc, FoundFlag);
10922 
10923  if(!FoundFlag)
10924  {
10925  throw Exception("Error, FoundFlag false in PlatformOnSignalSide after IsPlatformOrNamedNonStationLocationPresent called successfully");
10926  }
10927  TTrackElement IAElement;
10928 
10929  if(SpeedTag == 68) // top sig
10930  {
10931  if((InactiveTrackElementAt(22, IMPair.first).SpeedTag == 76) || (InactiveTrackElementAt(23, IMPair.second).SpeedTag == 76)) // top plat
10932  {
10933  if(InactiveTrackElementAt(49, IMPair.first).SpeedTag == 76)
10934  {
10935  IAElement = InactiveTrackElementAt(50, IMPair.first);
10936  }
10937  else
10938  {
10939  IAElement = InactiveTrackElementAt(51, IMPair.second);
10940  }
10941  if(IAElement.LocationName == "")
10942  {
10943 // SignalPlatformGraphic = RailGraphics->Plat68Striped;
10944  SignalPlatformGraphic = RailGraphics->gl76Striped;
10945  }
10946  else
10947  {
10948 // SignalPlatformGraphic = RailGraphics->Plat68;
10949  SignalPlatformGraphic = RailGraphics->gl76;
10950  }
10951  Utilities->CallLogPop(950);
10952  return(true);
10953  }
10954  }
10955  else if(SpeedTag == 69) // bot sig
10956  {
10957  if((InactiveTrackElementAt(70, IMPair.first).SpeedTag == 77) || (InactiveTrackElementAt(75, IMPair.second).SpeedTag == 77)) // bot plat
10958  {
10959  if(InactiveTrackElementAt(76, IMPair.first).SpeedTag == 77)
10960  {
10961  IAElement = InactiveTrackElementAt(77, IMPair.first);
10962  }
10963  else
10964  {
10965  IAElement = InactiveTrackElementAt(78, IMPair.second);
10966  }
10967  if(IAElement.LocationName == "")
10968  {
10969 // SignalPlatformGraphic = RailGraphics->Plat69Striped;
10970  SignalPlatformGraphic = RailGraphics->bm77Striped;
10971  }
10972  else
10973  {
10974 // SignalPlatformGraphic = RailGraphics->Plat69;
10975  SignalPlatformGraphic = RailGraphics->bm77;
10976  }
10977  Utilities->CallLogPop(951);
10978  return(true);
10979  }
10980  }
10981  else if(SpeedTag == 70) // left sig
10982  {
10983  if((InactiveTrackElementAt(52, IMPair.first).SpeedTag == 78) || (InactiveTrackElementAt(79, IMPair.second).SpeedTag == 78)) // left plat
10984  {
10985  if(InactiveTrackElementAt(80, IMPair.first).SpeedTag == 78)
10986  {
10987  IAElement = InactiveTrackElementAt(55, IMPair.first);
10988  }
10989  else
10990  {
10991  IAElement = InactiveTrackElementAt(82, IMPair.second);
10992  }
10993  if(IAElement.LocationName == "")
10994  {
10995 // SignalPlatformGraphic = RailGraphics->Plat70Striped;
10996  SignalPlatformGraphic = RailGraphics->bm78Striped;
10997  }
10998  else
10999  {
11000 // SignalPlatformGraphic = RailGraphics->Plat70;
11001  SignalPlatformGraphic = RailGraphics->bm78;
11002  }
11003  Utilities->CallLogPop(952);
11004  return(true);
11005  }
11006  }
11007  else if(SpeedTag == 71) // right sig
11008  {
11009  if((InactiveTrackElementAt(83, IMPair.first).SpeedTag == 79) || (InactiveTrackElementAt(58, IMPair.second).SpeedTag == 79)) // right plat
11010  {
11011  if(InactiveTrackElementAt(84, IMPair.first).SpeedTag == 79)
11012  {
11013  IAElement = InactiveTrackElementAt(85, IMPair.first);
11014  }
11015  else
11016  {
11017  IAElement = InactiveTrackElementAt(86, IMPair.second);
11018  }
11019  if(IAElement.LocationName == "")
11020  {
11021 // SignalPlatformGraphic = RailGraphics->Plat71Striped;
11022  SignalPlatformGraphic = RailGraphics->gl79Striped;
11023  }
11024  else
11025  {
11026 // SignalPlatformGraphic = RailGraphics->Plat71;
11027  SignalPlatformGraphic = RailGraphics->gl79;
11028  }
11029  Utilities->CallLogPop(953);
11030  return(true);
11031  }
11032  }
11033  Utilities->CallLogPop(954);
11034  return(false);
11035 }
11036 
11037 // ---------------------------------------------------------------------------
11038 
11039 bool TTrack::OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
11040 // returns true if another train on NextEntryPos track of element at NextPos, whether bridge or not
11041 // false if not, if NextPos == -1, or if only own train on the track
11042 {
11043  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OtherTrainOnTrack," + AnsiString(NextPos) + "," +
11044  AnsiString(NextEntryPos) + "," + AnsiString(OwnTrainID));
11045  if(NextEntryPos < 0)
11046  {
11047  Utilities->CallLogPop(1348);
11048  return(false);
11049  }
11050  TTrackElement TrackElement = TrackElementAt(713, NextPos);
11051 
11052  if(TrackElement.TrackType != Bridge)
11053  {
11054  Utilities->CallLogPop(1349);
11055  return ((TrackElement.TrainIDOnElement > -1) && (TrackElement.TrainIDOnElement != OwnTrainID));
11056  }
11057 // bridge if reach here
11058  if(NextEntryPos > 1)
11059  {
11060  Utilities->CallLogPop(1350);
11061  return ((TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1) && (TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 != OwnTrainID));
11062  }
11063  else
11064  {
11065  Utilities->CallLogPop(1351);
11066  return ((TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1) && (TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 != OwnTrainID));
11067  }
11068 }
11069 
11070 // ---------------------------------------------------------------------------
11071 
11073 {
11074  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SelectVectorAt," + AnsiString(At));
11075  if((At < 0) || ((unsigned int)At >= SelectVectorSize()))
11076  {
11077  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in SelectVectorAt");
11078  }
11079  Utilities->CallLogPop(1483);
11080  return(SelectVector.at(At));
11081 }
11082 
11083 // ---------------------------------------------------------------------------
11084 
11085 bool TTrack::IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
11086 // For element at HLoc & VLoc, returns true if there is an element adjacent to LinkIn
11087 {
11088  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsATrackElementAdjacentToLink," + AnsiString(HLocIn) + "," +
11089  AnsiString(VLocIn) + "," + AnsiString(LinkIn));
11090  bool FoundFlag = false;
11091  int NewHLoc = HLocIn + LinkHVArray[LinkIn][0];
11092  int NewVLoc = VLocIn + LinkHVArray[LinkIn][1];
11093 
11094  GetVectorPositionFromTrackMap(41, NewHLoc, NewVLoc, FoundFlag);
11095  Utilities->CallLogPop(1538);
11096  return(FoundFlag);
11097 }
11098 
11099 // ---------------------------------------------------------------------------
11100 
11101 bool TTrack::FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
11102 {
11103 // return true if find an inactive element called 'Name'
11104  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindHighestAndLowestNamedElements," + Name);
11105  int VLocHi = -2000000000, VLocLo = 2000000000, HLoc = 2000000000;
11106  bool FoundFlag = false;
11107 
11108  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
11109  {
11110  if(InactiveTrackElementAt(158, x).LocationName == Name)
11111  {
11112  FoundFlag = true;
11113  int V = InactiveTrackElementAt(159, x).VLoc;
11114  int H = InactiveTrackElementAt(160, x).HLoc;
11115  if(V > VLocHi)
11116  {
11117  VLocHi = V;
11118  }
11119  if(V < VLocLo)
11120  {
11121  VLocLo = V;
11122  }
11123  if(H < HLoc)
11124  {
11125  HLoc = H;
11126  }
11127  }
11128  }
11129  if(FoundFlag)
11130  {
11131  VPosHi = 16 * VLocHi;
11132  VPosLo = 16 * VLocLo;
11133  HPos = 16 * HLoc;
11134  Utilities->CallLogPop(1562);
11135  return(true);
11136  }
11137  else
11138  {
11139  Utilities->CallLogPop(1563);
11140  return(false);
11141  }
11142 }
11143 
11144 // ---------------------------------------------------------------------------
11145 
11146 int TTrack::FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
11147 {
11148 // return the link array position for the element at StartTVPosition that gives the closest link to the element at EndTVPosition
11149 // NB the StartTVPosition is expected to be a single track element as only positions 0 & 1 are checked
11150  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindClosestLinkPosition," + AnsiString(StartTVPosition) + "," +
11151  AnsiString(EndTVPosition));
11152  TTrackElement &StartElement = TrackElementAt(839, StartTVPosition);
11153  TTrackElement &EndElement = TrackElementAt(840, EndTVPosition);
11154 
11155 // get H & V values for the element adjacent to Link[0] & Link[1]
11156  int NewHLocLink0 = StartElement.HLoc + LinkHVArray[StartElement.Link[0]][0];
11157  int NewVLocLink0 = StartElement.VLoc + LinkHVArray[StartElement.Link[0]][1];
11158  int NewHLocLink1 = StartElement.HLoc + LinkHVArray[StartElement.Link[1]][0];
11159  int NewVLocLink1 = StartElement.VLoc + LinkHVArray[StartElement.Link[1]][1];
11160 
11161 // compute the sum of the squares of the H & V distances between EndElement and 'New' values
11162  int Link0Squares = ((EndElement.HLoc - NewHLocLink0) * (EndElement.HLoc - NewHLocLink0)) +
11163  ((EndElement.VLoc - NewVLocLink0) * (EndElement.VLoc - NewVLocLink0));
11164  int Link1Squares = ((EndElement.HLoc - NewHLocLink1) * (EndElement.HLoc - NewHLocLink1)) +
11165  ((EndElement.VLoc - NewVLocLink1) * (EndElement.VLoc - NewVLocLink1));
11166 
11167  if(Link0Squares <= Link1Squares)
11168  {
11169  Utilities->CallLogPop(1851);
11170  return(0);
11171  }
11172  else
11173  {
11174  Utilities->CallLogPop(1852);
11175  return(1);
11176  }
11177 }
11178 
11179 // ---------------------------------------------------------------------------
11180 
11181 int TTrack::GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
11182 {
11183  // element can be points or any other type
11184  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAnyElementOppositeLinkPos," + AnsiString(TrackVectorPosition) + "," +
11185  AnsiString(LinkPos));
11186  Derail = false;
11187  TTrackElement &TE = Track->TrackElementAt(277, TrackVectorPosition);
11188 
11189  if((TE.TrackType == Points) && (TE.Config[LinkPos] == Lead))
11190  {
11191  if(TE.Attribute == 0)
11192  {
11193  Utilities->CallLogPop(663);
11194  return(1); // Att == 0 & ExitPos == 1 represent straight
11195  }
11196  else
11197  {
11198  Utilities->CallLogPop(664);
11199  return(3); // Att == 1 & ExitPos == 3 represent diverging
11200  }
11201  }
11202  else if((TE.TrackType == Points) && (TE.Config[LinkPos] == Trail))
11203  {
11204  if((LinkPos == 1) && (TE.Attribute == 0))
11205  {
11206  Utilities->CallLogPop(665);
11207  return(0); // Att == 0 represents straight
11208  }
11209  else if(LinkPos == 1)
11210  {
11211  Derail = true;
11212  Utilities->CallLogPop(666);
11213  return(0);
11214  }
11215  else if((LinkPos == 3) && (TE.Attribute == 1))
11216  {
11217  Utilities->CallLogPop(667);
11218  return(0);
11219  }
11220  else if(LinkPos == 3)
11221  {
11222  Derail = true;
11223  Utilities->CallLogPop(668);
11224  return(0);
11225  }
11226  }
11227  else if(LinkPos == 0)
11228  {
11229  Utilities->CallLogPop(669);
11230  return(1);
11231  }
11232  else if(LinkPos == 1)
11233  {
11234  Utilities->CallLogPop(670);
11235  return(0);
11236  }
11237  else if(LinkPos == 2)
11238  {
11239  Utilities->CallLogPop(671);
11240  return(3);
11241  }
11242  else if(LinkPos == 3)
11243  {
11244  Utilities->CallLogPop(672);
11245  return(2);
11246  }
11247  throw Exception("Error, failure in GetExitPos"); // should never reach here
11248 }
11249 
11250 // ----------------------------------------------------------------------------
11251 
11253 {
11254  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateLCVector");
11255  LCVector.clear();
11256  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
11257  {
11258  if(InactiveTrackElementAt(161, x).TrackType == LevelCrossing)
11259  {
11260  LCVector.push_back(x);
11261  }
11262  }
11263  Utilities->CallLogPop(1931);
11264  return;
11265 }
11266 
11267 // ---------------------------------------------------------------------------
11268 
11269 bool TTrack::TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID) // new at v1.2.0
11270 /*
11271  Call GetVectorPositionFromTrackMap to identify the track element, then check if TrainIDOnElement > -1 (if a
11272  bridge then check relevant TrainID according to the Link), and if absent return false. If present identify
11273  the train using TrainController->TrainVectorAtIdent, and check which bit on the element in question (Lead, Mid or Lag),
11274  and then check the relevant EntryPos & ExitPos for a match with Link. If find a match return true and return the TrainID.
11275 */
11276 {
11277  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrainOnLink," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
11278  AnsiString(Link));
11279  bool FoundFlag;
11280 
11281  TrainID = -1;
11282  int VecPos = GetVectorPositionFromTrackMap(47, HLoc, VLoc, FoundFlag);
11283 
11284  if(!FoundFlag)
11285  {
11286  Utilities->CallLogPop(2001);
11287  return(false);
11288  }
11289  TTrackElement TE = TrackElementAt(882, VecPos);
11290 
11291  TrainID = TE.TrainIDOnElement;
11292  if(TE.TrackType == Bridge)
11293  {
11294  if(TE.TrainIDOnElement > -1)
11295  {
11296  if((TE.Link[0] == Link) || (TE.Link[1] == Link))
11297  {
11299  }
11300  else if((TE.Link[2] == Link) || (TE.Link[3] == Link))
11301  {
11303  }
11304  else
11305  {
11306  TrainID = -1; // shouldn't ever reach here but be safe
11307  }
11308  }
11309  }
11310  if(TrainID == -1)
11311  {
11312  Utilities->CallLogPop(2002);
11313  return(false);
11314  }
11315 // now get the train
11316  TTrain Train = TrainController->TrainVectorAtIdent(38, TrainID);
11317 
11318  if(Train.LinkOccupied(0, VecPos, Link)) // checks whether any part of train occupying Link on VecPos
11319  {
11320  Utilities->CallLogPop(2003);
11321  return(true);
11322  }
11323  TrainID = -1;
11324  Utilities->CallLogPop(2004);
11325  return(false);
11326 }
11327 
11328 // ---------------------------------------------------------------------------
11329 
11330 bool TTrack::DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
11331 /* New at v1.2.0
11332  As DiagonalFouledByRouteOrTarin but checks for a train only (may or may not be a route) and returns the ID number. Enter with H & V set for the element whose diagonal
11333  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
11334  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
11335  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
11336  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
11337  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
11338  Each of these is examined in turn for each route element in the relevant position.
11339 */
11340 {
11341  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByTrain," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
11342  "," + AnsiString(DiagonalLinkNumber));
11343  TrainID = -1;
11344  TPrefDirElement TempPrefDirElement;
11345  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
11346 
11347  if(((DiagonalLinkNumber == 1) && TrainOnLink(8, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && TrainOnLink(9, HLoc - 1, VLoc, 9, TrainID)))
11348  {
11349  Utilities->CallLogPop(2027);
11350  return(true);
11351  }
11352  if(((DiagonalLinkNumber == 1) && TrainOnLink(10, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && TrainOnLink(11, HLoc, VLoc - 1, 9, TrainID)))
11353  {
11354  Utilities->CallLogPop(2028);
11355  return(true);
11356  }
11357  if(((DiagonalLinkNumber == 3) && TrainOnLink(12, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(13, HLoc + 1, VLoc, 7, TrainID)))
11358  {
11359  Utilities->CallLogPop(2029);
11360  return(true);
11361  }
11362  if(((DiagonalLinkNumber == 7) && TrainOnLink(14, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(15, HLoc, VLoc + 1, 3, TrainID)))
11363  {
11364  Utilities->CallLogPop(2030);
11365  return(true);
11366  }
11367  Utilities->CallLogPop(2031);
11368  return(false);
11369 }
11370 
11371 // ---------------------------------------------------------------------------
11372 
11373 void TTrack::SaveUserGraphics(int Caller, std::ofstream &VecFile)
11374 {
11375  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveUserGraphics");
11376  Utilities->SaveFileInt(VecFile, UserGraphicVector.size()); // number of items
11377  TUserGraphicItem UGI;
11378  AnsiString JustFileName = "";
11379 
11380  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
11381  {
11382  UGI = UserGraphicVectorAt(17, x);
11383  int LastDelim = UGI.FileName.LastDelimiter('\\');
11384  if(LastDelim == 0) // can't find it so skip this item
11385  {
11386  continue;
11387  }
11388  else
11389  {
11390  JustFileName = UGI.FileName.SubString(LastDelim + 1, UGI.FileName.Length() - LastDelim);
11391  }
11392  Utilities->SaveFileString(VecFile, JustFileName);
11393  Utilities->SaveFileInt(VecFile, UGI.HPos);
11394  Utilities->SaveFileInt(VecFile, UGI.VPos);
11395  }
11396  Utilities->CallLogPop(2178);
11397 }
11398 
11399 // ---------------------------------------------------------------------------
11400 
11401 int TTrack::NumberOfPlatforms(int Caller, AnsiString LocationName)
11402 //checks all active track elements and lists those with ActiveTrackElementName same as LocationName in NamePosVector
11403 {
11404  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfPlatforms," + LocationName);
11405  int NumPlats = 0;
11406  TTrackElement TempElement;
11407  int TempInt;
11408 
11409  typedef std::list<int> TNamePosList;
11410  TNamePosList NamePosList;
11411  typedef TNamePosList::iterator TNPLIt;
11412  TNPLIt NPLIt;
11413  typedef std::list<int> TOnePlatList;
11414  TOnePlatList OnePlatList;
11415  typedef TOnePlatList::iterator TOPLIt;
11416  TOPLIt OPLIt;
11417 
11418  NamePosList.clear();
11419  OnePlatList.clear();
11420  for(unsigned int x = 0; x < TrackVector.size(); x++)
11421  {
11422  if(TrackElementAt(988, x).ActiveTrackElementName == LocationName)
11423  {
11424  NamePosList.push_back(x);
11425  }
11426  }
11427  //NamePosList complete
11428 
11429  if(!NamePosList.empty()) //first value for the loop examination
11430  {
11431  OnePlatList.push_back(NamePosList.back());
11432  NamePosList.pop_back(); //erase from NPV as done with it here
11433  }
11434  while(!OnePlatList.empty()) //loop to examine all linked elements
11435  {
11436  TempInt = OnePlatList.front();
11437  TempElement = TrackElementAt(989, TempInt);
11438 
11439  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[0]);
11440  if(NPLIt != NamePosList.end() && ((TempElement.Link[0] == 2) || (TempElement.Link[0] == 4) || (TempElement.Link[0] == 6) || (TempElement.Link[0] == 8)))
11441  {
11442  OnePlatList.push_back(TempElement.Conn[0]);
11443  NamePosList.erase(NPLIt);
11444  }
11445  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[1]);
11446  if(NPLIt != NamePosList.end() && ((TempElement.Link[1] == 2) || (TempElement.Link[1] == 4) || (TempElement.Link[1] == 6) || (TempElement.Link[1] == 8)))
11447  {
11448  OnePlatList.push_back(TempElement.Conn[1]);
11449  NamePosList.erase(NPLIt);
11450  }
11451  //here when loaded any connecting links into OnePlatList, so can erase the front element
11452  OnePlatList.erase(OnePlatList.begin());
11453  if(OnePlatList.empty())
11454  {
11455  NumPlats++; //finished with current linked elements so can increment NumPlats
11456  if(!NamePosList.empty())
11457  {
11458  OnePlatList.push_back(NamePosList.back()); //ready for next iteration
11459  NamePosList.pop_back(); //erase from NPV as done with it there
11460  }
11461  }
11462  }
11463  Utilities->CallLogPop(2218);
11464  return(NumPlats);
11465 }
11466 
11467 // ---------------------------------------------------------------------------
11468 
11469 void TTrack::RepairFailedSignals(TFailedElementVector::iterator FPVIt) //added at v2.13.0
11470 {//repair Signals pointed to by FPVIt
11471  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairFailedSignals," + AnsiString(FPVIt->TVPos));
11472  TTrackElement &TE = Track->TrackElementAt(1516, FPVIt->TVPos);
11473  if(TE.TrackType != SignalPost)
11474  {
11475  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not signal in RepairFailedSignals");
11476  }
11477  if(!TE.Failed)
11478  {
11479  throw Exception("Signals not failed at " + AnsiString(FPVIt->TVPos) + " in RepairFailedSignals");
11480  }
11481  TE.Failed = false;
11482  //set to correct aspect
11483  int RouteNumber;
11484  if(AllRoutes->GetRouteTypeAndNumber(40, FPVIt->TVPos, 0, RouteNumber) != TAllRoutes::NoRoute) //otherwise Attribute already 0 so will plot red
11485  { // 0 for LinkPos ok as a signal so only one track
11486  AllRoutes->AllRoutesVector.at(RouteNumber).SetRouteSignals(11);
11487  }
11488  //erase from vector
11489  Track->FailedSignalsVector.erase(FPVIt);
11490 
11491  Display->WarningLog(20, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal at " + TE.ElementID + " restored to full working order");
11492  PerfLogForm->PerformanceLog(43, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal at " + TE.ElementID + " restored to full working order");
11493  TrainController->StopTTClockMessage(130, "Signal at " + TE.ElementID + " restored to full working order.");
11494  AllRoutes->RebuildRailwayFlag = true;
11495  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot Signals without failed graphic
11496  Utilities->CallLogPop(2519);
11497 }
11498 
11499 // ---------------------------------------------------------------------------
11500 
11501 void TTrack::RepairFailedPoints(TFailedElementVector::iterator FPVIt) //added at v2.13.0
11502 {//repair points pointed to by FPVIt
11503  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairFailedPoints," + AnsiString(FPVIt->TVPos));
11504  TTrackElement &TE = Track->TrackElementAt(1505, FPVIt->TVPos);
11505  if(TE.TrackType != Points)
11506  {
11507  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not points in RepairFailedPoints");
11508  }
11509  if(!TE.Failed)
11510  {
11511  throw Exception("Points not failed at " + AnsiString(FPVIt->TVPos) + " in RepairFailedPoints");
11512  }
11513  TE.Failed = false;
11518  //erase from vector
11519  Track->FailedPointsVector.erase(FPVIt);
11520 
11521  Display->WarningLog(15, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points at " + TE.ElementID + " restored to full working order");
11522  PerfLogForm->PerformanceLog(38, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points at " + TE.ElementID + " restored to full working order");
11523  TrainController->StopTTClockMessage(123, "Points at " + TE.ElementID + " restored to full working order.");
11524  AllRoutes->RebuildRailwayFlag = true;
11525  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot points without failed graphic
11526  Utilities->CallLogPop(2518);
11527 }
11528 
11529 // ---------------------------------------------------------------------------
11530 
11531 void TTrack::RepairTSR(TFailedElementVector::iterator FPVIt) //added at v2.13.0
11532 {//repair points pointed to by FPVIt
11533  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairTSR," + AnsiString(FPVIt->TVPos));
11534  TTrackElement &TE = Track->TrackElementAt(1535, FPVIt->TVPos);
11535  if(TE.TrackType != Simple)
11536  {
11537  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not simple in RepairFailedPoints");
11538  }
11539  if(!TE.Failed)
11540  {
11541  throw Exception("No TSR at " + AnsiString(FPVIt->TVPos) + " in RepairTSR");
11542  }
11543  TE.Failed = false;
11546  //erase from vector
11547  Track->TSRVector.erase(FPVIt);
11548 
11549  Display->WarningLog(21, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order");
11550  PerfLogForm->PerformanceLog(44, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order");
11551  TrainController->StopTTClockMessage(131, "Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order.");
11552  AllRoutes->RebuildRailwayFlag = true;
11553  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot points without failed graphic
11554  Utilities->CallLogPop(2520);
11555 }
11556 
11557 // ---------------------------------------------------------------------------
11558 
11560 {
11561  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PopulateSimpleVector");
11562  SimpleVector.clear();
11563  for(unsigned int x = 0; x < TrackVector.size(); x++)
11564  {
11565  if(TrackElementAt(1517, x).TrackType == Simple)
11566  {
11567  SimpleVector.push_back(int(x));
11568  }
11569  }
11570  Utilities->CallLogPop(2521);
11571 }
11572 
11573 // ---------------------------------------------------------------------------
11574 // UserGraphic, PrefDir & Route functions
11575 // ---------------------------------------------------------------------------
11576 
11578 {
11579  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicVectorAt," + AnsiString(At));
11580  if((At < 0) || ((unsigned int)At >= UserGraphicVector.size()))
11581  {
11582  throw Exception("Out of Range Error, vector size: " + AnsiString(UserGraphicVector.size()) + ", At: " + AnsiString(At) + " in UserGraphicVectorAt");
11583  }
11584  Utilities->CallLogPop(2194);
11585  return(UserGraphicVector.at(At));
11586 }
11587 
11588 // ---------------------------------------------------------------------------
11589 
11590 int TOnePrefDir::LastElementNumber(int Caller) const
11591 {
11592  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementNumber,");
11593  int RetVal = PrefDirVector.size() - 1;
11594 
11595  if(RetVal < 0)
11596  {
11597  throw Exception("Return value negative in call to LastElementNumber");
11598  }
11599  Utilities->CallLogPop(114);
11600  return(RetVal);
11601 }
11602 
11603 // ---------------------------------------------------------------------------
11605 {
11606  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementPtr,");
11607  if(PrefDirVector.empty())
11608  {
11609  throw Exception("PrefDirVector empty in call to LastElementPtr");
11610  }
11611  TPrefDirVectorIterator RetIT = PrefDirVector.end() - 1;
11612 
11613  Utilities->CallLogPop(115);
11614  return(RetIT);
11615 }
11616 
11617 // ---------------------------------------------------------------------------
11619 {
11620  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedPrefDirElementAt," + AnsiString(At));
11621  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
11622  {
11623  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) + " in GetFixedPrefDirElementAt");
11624  }
11625  Utilities->CallLogPop(116);
11626  return(PrefDirVector.at(At));
11627 }
11628 
11629 // ---------------------------------------------------------------------------
11631 {
11632  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiablePrefDirElementAt," + AnsiString(At));
11633  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
11634  {
11635  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) +
11636  " in GetModifiablePrefDirElementAt");
11637  }
11638  Utilities->CallLogPop(117);
11639  return(PrefDirVector.at(At));
11640 }
11641 
11642 // ---------------------------------------------------------------------------
11644 {
11645  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedSearchElementAt," + AnsiString(At));
11646  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
11647  {
11648  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetFixedSearchElementAt");
11649  }
11650  Utilities->CallLogPop(118);
11651  return(SearchVector.at(At));
11652 }
11653 
11654 // ---------------------------------------------------------------------------
11656 {
11657  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableSearchElementAt," + AnsiString(At));
11658  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
11659  {
11660  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableSearchElementAt");
11661  }
11662  Utilities->CallLogPop(119);
11663  return(SearchVector.at(At));
11664 }
11665 
11666 // ---------------------------------------------------------------------------
11667 bool TOnePrefDir::GetPrefDirStartElement(int Caller, int HLoc, int VLoc) // Return true if OK.
11668 /*
11669  Enter with HLoc & VLoc set to selected element. Clear PrefDirVector, check if selected element
11670  is a valid track element & return false if not. Create a TPrefDirElement from the track element and
11671  set checkcount to 4 to cover the fixed values, then add to PrefDirVector. All variable values are
11672  set in later functions.
11673 */
11674 {
11675  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirStartElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
11676  ClearPrefDir();
11677  int TrackVectorPosition;
11678  TTrackElement TrackElement;
11679 
11680  if(!(Track->FindNonPlatformMatch(5, HLoc, VLoc, TrackVectorPosition, TrackElement)))
11681  {
11682  Utilities->CallLogPop(126);
11683  return(false);
11684  }
11685 /* it can be points so drop the code below - all exits are checked, no assumptions are made about the exit position of the start element
11686  if(TrackElement.TrackType == Points)
11687  {
11688  ShowMessage("Can't start on points");//because if PrefDir leads away from the leading edge
11689  //it isn't known which trailing edge is the required PrefDir - could use the straight as
11690  //default but may already be a PrefDir up to the diverging edge, then will have a mismatch,
11691  //best to prevent it to avoid problems
11692  Utilities->CallLogPop(127);
11693  return false;
11694  }
11695 */
11696  TPrefDirElement PrefDirElement(TrackElement);
11697 
11698  PrefDirElement.TrackVectorPosition = TrackVectorPosition;
11699  PrefDirElement.CheckCount = 4; // HLoc, VLoc, SpeedTag & TrackVectorPosition
11700  StorePrefDirElement(1, PrefDirElement); // enter first element
11701 // Note that ELink not set even if a buffer or continuation - these set in
11702 // ConvertPrefDirSearchVector after 2nd element added
11703 
11704  Utilities->CallLogPop(128);
11705  return(true);
11706 }
11707 
11708 // ---------------------------------------------------------------------------
11709 bool TOnePrefDir::GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
11710 
11711 /*
11712  Enter with HLoc & VLoc set to selected element. If not a track element or if PrefDirVector empty return false.
11713  Examine the last element in the PrefDirVector, if ELink not set (start element) do an immediate
11714  check for an adjacent find (i.e. find selected element), & if succeed use SearchForPrefDir with that as XLinkPos to deal
11715  with setting the PrefDir vector, & return true.
11716  If last element was the start element but no immediate find, search on each valid exit pos in turn, using
11717  SearchForPrefDir to examine all branches. If succeed set PrefDirVector.
11718  Otherwise (last element not start element) check if last element was a leading point (if so can't be first element)
11719  & check again for an immediate find on either XLinkPos values 1 & 3, using SearchForPrefDir &
11720  ConvertPrefDirSearchVector to set PrefDirVector.
11721  If a leading point but not an immediate find use SearchForPrefDir on the XLinkPos values 1 & 3 in turn.
11722  If it wasn't a leading point just use XLinkPos value corresponding to XLink & Search on that. If don't
11723  find the required element return false. CheckCount is used to keep track of set values to allow check later.
11724 */
11725 
11726 {
11727  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPrefDirElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
11728  FinishElement = false;
11729  int TrackVectorPosition;
11730 
11731  TotalSearchCount = 0;
11732  TTrackElement TrackElement, TempTrackElement;
11733 
11734  if(PrefDirVector.size() == 0)
11735  {
11736  Utilities->CallLogPop(129);
11737  return(false);
11738  }
11739  if(!(Track->FindNonPlatformMatch(6, HLoc, VLoc, TrackVectorPosition, TrackElement)))
11740  {
11741  Utilities->CallLogPop(130);
11742  return(false);
11743  }
11744 // set the search limits using the last stored element in PrefDirVector as the start point
11745 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
11746 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
11747 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
11748 
11749  TPrefDirElement StartPrefDirElement = PrefDirVector.at(LastElementNumber(72));
11750 
11751  if(TrackElement.HLoc >= StartPrefDirElement.HLoc)
11752  {
11753  SearchLimitLowH = StartPrefDirElement.HLoc - 15;
11754  SearchLimitHighH = TrackElement.HLoc + 15;
11755  }
11756  else
11757  {
11758  SearchLimitLowH = TrackElement.HLoc - 15;
11759  SearchLimitHighH = StartPrefDirElement.HLoc + 15;
11760  }
11761  if(TrackElement.VLoc >= StartPrefDirElement.VLoc)
11762  {
11763  SearchLimitLowV = StartPrefDirElement.VLoc - 15;
11764  SearchLimitHighV = TrackElement.VLoc + 15;
11765  }
11766  else
11767  {
11768  SearchLimitLowV = TrackElement.VLoc - 15;
11769  SearchLimitHighV = StartPrefDirElement.VLoc + 15;
11770  }
11771 /* dropped this for v0.4d - prevents ability to set paths for gaps that are widely separated, ok without it as search limited by SearchVector size
11772  check & TotalSearchCounts check
11773  if((abs(TrackElement.HLoc - StartPrefDirElement.HLoc) > 120) || (abs(TrackElement.VLoc - StartPrefDirElement.VLoc) > 120))
11774  {
11775  ShowMessage("Unable to reach the selected element - too far ahead");
11776  Utilities->CallLogPop(1692);
11777  return false;
11778  }
11779 */
11780 // get last PrefDir element
11781  if(PrefDirVector.at(LastElementNumber(0)).ELink == -1) // start element
11782  {
11783  // check if TrackElement adjacent to any of the 4 XLinkPos'
11784  for(int x = 0; x < 4; x++)
11785  {
11786  if(PrefDirVector.at(LastElementNumber(1)).Conn[x] == TrackVectorPosition)
11787  {
11788  PrefDirVector.at(LastElementNumber(2)).XLinkPos = x;
11789  PrefDirVector.at(LastElementNumber(3)).XLink = PrefDirVector.at(LastElementNumber(4)).Link[x];
11790  PrefDirVector.at(LastElementNumber(5)).CheckCount++;
11791  PrefDirVector.at(LastElementNumber(6)).CheckCount++;
11792  break; // can have 2 connections if have 2 adjacent gaps connected to each other but ELink & XLink
11793  // then ambiguous. Have to opt for just one, and if user wanted the other then that's unfortunate,
11794  // shouldn't ever get it in a serious railway though.
11795 // Note: ELink & ELinkPos are set in ConvertPrefDirSearchVector for the start element
11796  }
11797  }
11798  if(PrefDirVector.at(LastElementNumber(7)).XLinkPos > -1) // i.e required position must be adjacent to the start element
11799  {
11800  TempTrackElement = PrefDirVector.at(LastElementNumber(8));
11801  SearchVector.clear(); // use this & convert to set all PrefDir element values
11802  if(SearchForPrefDir(1, TempTrackElement, PrefDirVector.at(LastElementNumber(9)).XLinkPos, TrackVectorPosition))
11803  {
11805  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11806  {
11807  FinishElement = true;
11808  }
11809  Utilities->CallLogPop(131);
11810  return(true);
11811  }
11812  } // not an adjacent element
11813 
11814  // now check each of the 4 possible XLinkPos values
11815  for(int x = 0; x < 4; x++)
11816  {
11817  if((PrefDirVector.at(LastElementNumber(10)).Link[x] > 0) && (PrefDirVector.at(LastElementNumber(11)).Config[x] != End)) // i.e have somewhere to go
11818  {
11819  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find the required position
11820  TempTrackElement = PrefDirVector.at(LastElementNumber(12));
11821  SearchVector.clear();
11822  if(SearchForPrefDir(2, TempTrackElement, x, TrackVectorPosition))
11823  {
11825  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11826  {
11827  FinishElement = true;
11828  }
11829  Utilities->CallLogPop(132);
11830  return(true);
11831  }
11832  }
11833  } // here if checked all possible exits without success
11834  ShowMessage(
11835  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
11836  Utilities->CallLogPop(133);
11837  return(false);
11838  }
11839 // dealt above with LastPrefDirElement being the start element (which can be points)
11840 
11841  if((PrefDirVector.at(LastElementNumber(13)).TrackType == Points) && (PrefDirVector.at(LastElementNumber(14)).Config[PrefDirVector.at(LastElementNumber(15))
11842  .ELinkPos] == Lead)) // leading point
11843  {
11844  if(PrefDirVector.at(LastElementNumber(16)).Conn[1] == TrackVectorPosition) // found it next to XLinkPos = 1
11845  {
11846  PrefDirVector.at(LastElementNumber(17)).XLinkPos = 1;
11847  PrefDirVector.at(LastElementNumber(18)).XLink = PrefDirVector.at(LastElementNumber(19)).Link[1];
11848  // can't be buffers or gap if points
11849  PrefDirVector.at(LastElementNumber(20)).CheckCount++;
11850  PrefDirVector.at(LastElementNumber(21)).CheckCount++;
11851  TempTrackElement = PrefDirVector.at(LastElementNumber(22));
11852  SearchVector.clear();
11853  if(SearchForPrefDir(3, TempTrackElement, 1, TrackVectorPosition)) // bound to return true
11854  {
11856  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11857  {
11858  FinishElement = true;
11859  }
11860  Utilities->CallLogPop(134);
11861  return(true);
11862  }
11863  }
11864  if(PrefDirVector.at(LastElementNumber(23)).Conn[3] == TrackVectorPosition) // found it next to XLinkPos = 3
11865  {
11866  PrefDirVector.at(LastElementNumber(24)).XLinkPos = 3;
11867  PrefDirVector.at(LastElementNumber(25)).XLink = PrefDirVector.at(LastElementNumber(26)).Link[3];
11868  PrefDirVector.at(LastElementNumber(27)).CheckCount++;
11869  PrefDirVector.at(LastElementNumber(28)).CheckCount++;
11870  TempTrackElement = PrefDirVector.at(LastElementNumber(29));
11871  SearchVector.clear();
11872  if(SearchForPrefDir(4, TempTrackElement, 3, TrackVectorPosition)) // bound to return true
11873  {
11875  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11876  {
11877  FinishElement = true;
11878  }
11879  Utilities->CallLogPop(135);
11880  return(true);
11881  }
11882  }
11883 // above dealt with immediate finds for leading point,
11884 // now deal with ordinary searches for leading point
11885  PrefDirVector.at(LastElementNumber(30)).XLinkPos = 1;
11886  PrefDirVector.at(LastElementNumber(31)).XLink = PrefDirVector.at(LastElementNumber(32)).Link[1];
11887  PrefDirVector.at(LastElementNumber(33)).CheckCount++;
11888  PrefDirVector.at(LastElementNumber(34)).CheckCount++;
11889  TempTrackElement = PrefDirVector.at(LastElementNumber(35));
11890  SearchVector.clear();
11891  if(SearchForPrefDir(5, TempTrackElement, 1, TrackVectorPosition))
11892  {
11894  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11895  {
11896  FinishElement = true;
11897  }
11898  Utilities->CallLogPop(136);
11899  return(true);
11900  }
11901  PrefDirVector.at(LastElementNumber(36)).XLinkPos = 3;
11902  PrefDirVector.at(LastElementNumber(37)).XLink = PrefDirVector.at(LastElementNumber(38)).Link[3];
11903  // note that CheckCount already increased to allow for XLinkPos & XLink
11904  TempTrackElement = PrefDirVector.at(LastElementNumber(39));
11905  SearchVector.clear();
11906  if(SearchForPrefDir(6, TempTrackElement, 3, TrackVectorPosition))
11907  {
11909  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11910  {
11911  FinishElement = true;
11912  }
11913  Utilities->CallLogPop(137);
11914  return(true);
11915  }
11916 // here if failed to find match for leading point
11917  PrefDirVector.at(LastElementNumber(69)).CheckCount--; // to removed the earlier increments for XLinkPos & XLink
11918  PrefDirVector.at(LastElementNumber(70)).CheckCount--;
11919  ShowMessage(
11920  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
11921  Utilities->CallLogPop(138);
11922  return(false);
11923  }
11924 // leading point fully dealt with above
11925 // here with an ordinary element, just do an ordinary search - no need to search for an immediate find
11926 // separately as covered in ordinary search.
11927 
11928  TempTrackElement = PrefDirVector.at(LastElementNumber(40));
11929  SearchVector.clear();
11930 // no need to check for valid XLinkPos as not start element and not end element or would not reach here
11931  if(SearchForPrefDir(7, TempTrackElement, PrefDirVector.at(LastElementNumber(41)).XLinkPos, TrackVectorPosition))
11932  {
11934  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11935  {
11936  FinishElement = true;
11937  }
11938  Utilities->CallLogPop(139);
11939  return(true);
11940  }
11941  ShowMessage(
11942  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
11943  Utilities->CallLogPop(140);
11944  return(false); // failed to find required element
11945 }
11946 
11947 // ---------------------------------------------------------------------------
11948 
11949 bool TOnePrefDir::SearchForPrefDir(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition)
11950 /*
11951  Enter with CurrentTrackElement stored in the PrefDirVector, XLinkPos set to the link
11952  to search on, & SearchVector cleared unless entered recursively. Function is a continuous loop that
11953  exits when find required element (returns true) or reaches a buffer or continuation or otherwise fails a search condition (returns false).
11954  Keep a count of entries in SearchVector during the current function call, so that this number can be
11955  erased for an unproductive branch search.
11956  Create a NextTrackElement from Current & XLinkPos as far as possible, & check if found required
11957  element. If so save it & return true. If not check if buffer, continuation, or earlier position
11958  in SearchVector or PrefDirVector, & if so erase all searchvector & return false. If OK check if a leading point and
11959  if so do up to 2 recursive searches for the 2 exits. If fail on both erase searchvector & return false.
11960  If not any of above, store element in searchvector, set the new current element values from the
11961  SearchElement, then go back to the while loop for the next step in the search.
11962 */
11963 {
11964  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPrefDir," + CurrentTrackElement.LogTrack(13) + "," +
11965  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition));
11966  int VectorCount = 0;
11967 
11968  while(true)
11969  {
11970  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
11971  {
11972  for(int x = 0; x < VectorCount; x++)
11973  {
11974  SearchVector.erase(SearchVector.end() - 1);
11975  }
11976  Utilities->CallLogPop(141);
11977  return(false);
11978  }
11979  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
11980  TTrackElement NextTrackElement = Track->TrackElementAt(74, NextPosition);
11981  TPrefDirElement SearchElement(NextTrackElement);
11982  SearchElement.TrackVectorPosition = NextPosition;
11983  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
11984  SearchElement.ELinkPos = NextELinkPos;
11985  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
11986  int NextXLinkPos;
11987  if(SearchElement.ELinkPos == 0)
11988  {
11989  NextXLinkPos = 1;
11990  }
11991  if(SearchElement.ELinkPos == 1)
11992  {
11993  NextXLinkPos = 0;
11994  }
11995  if(SearchElement.ELinkPos == 2)
11996  {
11997  NextXLinkPos = 3;
11998  }
11999  if(SearchElement.ELinkPos == 3)
12000  {
12001  NextXLinkPos = 2;
12002  }
12003  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
12004  {
12005  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
12006  // but may be buffers, continuation or gap
12007  SearchElement.XLinkPos = NextXLinkPos;
12008  }
12009 // can't set XLink or XLinkPos yet if the element is a leading point.
12010 // check if found it
12011  if(SearchElement.TrackVectorPosition == RequiredPosition)
12012  {
12013  SearchVector.push_back(SearchElement); // XLink & XLinkPos won't be set if a leading point
12014  VectorCount++; // not really needed but include for tidyness
12015  TotalSearchCount++;
12016  Utilities->CallLogPop(142);
12017  return(true);
12018  }
12019 // check if PrefDirVector > 200 and if so reject further searches (to avoid possible problems in converting
12020 // very long vectors) - warning given in ConvertPrefDirSearchVector, though can still add elements one
12021 // at a time - drop this
12022 /*
12023  if(PrefDirVector.size() > 200)
12024  {
12025  for(int x=0;x<VectorCount;x++) SearchVector.erase(SearchVector.end() - 1);
12026  Utilities->CallLogPop(1419);
12027  return false;
12028  }
12029 */
12030 // check if a buffer or continuation
12031  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
12032  {
12033  for(int x = 0; x < VectorCount; x++)
12034  {
12035  SearchVector.erase(SearchVector.end() - 1);
12036  }
12037  Utilities->CallLogPop(143);
12038  return(false);
12039  }
12040 // check if reached an earlier position on search PrefDir with same entry value
12041  for(unsigned int x = 0; x < SearchVector.size(); x++)
12042  {
12043  if((SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition) && (SearchElement.ELink == SearchVector.at(x).ELink))
12044  {
12045  for(int x = 0; x < VectorCount; x++)
12046  {
12047  SearchVector.erase(SearchVector.end() - 1);
12048  }
12049  Utilities->CallLogPop(144);
12050  return(false);
12051  }
12052  }
12053 // check if reached an earlier position in the PrefDirVector with same entry value (without this can keep adding entries
12054 // to PrefDir4MultiMap, and since only 4 are searched an error can occur)
12055  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12056  {
12057  if((SearchElement.TrackVectorPosition == PrefDirVector.at(x).TrackVectorPosition) && (SearchElement.ELink == PrefDirVector.at(x).ELink))
12058  {
12059  for(int x = 0; x < VectorCount; x++)
12060  {
12061  SearchVector.erase(SearchVector.end() - 1);
12062  }
12063  Utilities->CallLogPop(1417);
12064  return(false);
12065  }
12066  }
12067 
12068 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
12069 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
12070 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
12072  {
12073  for(int x = 0; x < VectorCount; x++)
12074  {
12075  SearchVector.erase(SearchVector.end() - 1);
12076  }
12077  Utilities->CallLogPop(1691);
12078  return(false);
12079  }
12080 // check if SearchVector reached 150, and if so reject, to save time in searching for PrefDirs
12081  if(SearchVector.size() > 150)
12082  {
12083  for(int x = 0; x < VectorCount; x++)
12084  {
12085  SearchVector.erase(SearchVector.end() - 1);
12086  }
12087  Utilities->CallLogPop(1418);
12088  return(false);
12089  }
12090 // check if reached a leading point
12091  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
12092  {
12093 // push element with XLink set to position [1]
12094  SearchElement.XLink = SearchElement.Link[1];
12095  SearchElement.XLinkPos = 1;
12096  SearchVector.push_back(SearchElement);
12097  VectorCount++;
12098  TotalSearchCount++;
12099  // recursive search at XLinkPos of 1 (i.e. 1st trailing exit)
12100  // Note that have to use a TTrackElement in the recursive search, so SearchElement
12101  // can't be used. NextTrackElement is the corresponding TTrackElement.
12102  if(SearchForPrefDir(8, NextTrackElement, 1, RequiredPosition))
12103  {
12104  Utilities->CallLogPop(145);
12105  return(true);
12106  }
12107  else
12108  {
12109 // remove leading point with XLinkPos [1]
12110  SearchVector.erase(SearchVector.end() - 1);
12111  VectorCount--;
12112 // push element with XLink set to position [3]
12113  SearchElement.XLink = SearchElement.Link[3];
12114  SearchElement.XLinkPos = 3;
12115  SearchVector.push_back(SearchElement);
12116  VectorCount++;
12117  TotalSearchCount++;
12118 // recursive search at XLinkPos of 3 (i.e. 2nd trailing exit)
12119  if(SearchForPrefDir(9, NextTrackElement, 3, RequiredPosition))
12120  {
12121  Utilities->CallLogPop(146);
12122  return(true);
12123  }
12124  else
12125  {
12126  for(int x = 0; x < VectorCount; x++)
12127  {
12128  SearchVector.erase(SearchVector.end() - 1);
12129  }
12130  Utilities->CallLogPop(147);
12131  return(false);
12132  }
12133  }
12134  } // if leading point
12135 
12136 // here if ordinary element, push it, inc vector & update CurrentTrackElement
12137 // ready for next element on PrefDir
12138  SearchVector.push_back(SearchElement);
12139  VectorCount++;
12140  TotalSearchCount++;
12141  XLinkPos = NextXLinkPos;
12142  CurrentTrackElement = SearchElement;
12143  } // while(true)
12144 }
12145 
12146 // ---------------------------------------------------------------------------
12147 
12149 /*
12150  Enter with SearchVector established. This contains ELink + Pos, XLink + Pos, & TrackVectorPosition
12151  for each element on the search PrefDir, though if the last element is a leading point
12152  then the final XLink won't be set.
12153  Note also that the last element in the PrefDirVector (as opposed to the searchvector) may not have its ELink set (if it was the start)
12154  nor its XLink set (if it was the start or a leading point), so these are checked first and together with EXNumber set as necessary.
12155  The remaining PrefDirVector elements are then set from the searchvector & checkcount keeps pace as values are added.
12156 */
12157 {
12158  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertPrefDirSearchVector");
12159  if(SearchVector.size() == 0)
12160  {
12161  throw Exception("Error, SearchVector empty");
12162  }
12163 // get first SearchElement in order to set last PrefDirelement
12164  TPrefDirElement SearchElement = SearchVector.at(0);
12165 
12166 // set last PrefDir element XLink & ELink values if not already set
12167 // ELink & XLink not set if was first element in PrefDir; XLink also not set if was a leading point
12168  for(int x = 0; x < 4; x++)
12169  {
12170  if(PrefDirVector.at(LastElementNumber(42)).Conn[x] == SearchElement.TrackVectorPosition)
12171  {
12172  if(PrefDirVector.at(LastElementNumber(43)).XLink == -1) // i.e. not set
12173  {
12174  PrefDirVector.at(LastElementNumber(44)).XLink = PrefDirVector.at(LastElementNumber(45)).Link[x];
12175  PrefDirVector.at(LastElementNumber(46)).XLinkPos = x;
12176  PrefDirVector.at(LastElementNumber(47)).CheckCount++;
12177  PrefDirVector.at(LastElementNumber(48)).CheckCount++;
12178  }
12179  int ELinkPos;
12180  if(PrefDirVector.at(LastElementNumber(49)).XLinkPos == 0)
12181  {
12182  ELinkPos = 1; // use actual value rather than 'x' as may be a gap
12183  }
12184  // with both ends linked to 1st searchvector element, & if XLink was set then x may not correspond
12185  if(PrefDirVector.at(LastElementNumber(50)).XLinkPos == 1)
12186  {
12187  ELinkPos = 0;
12188  }
12189  if(PrefDirVector.at(LastElementNumber(51)).XLinkPos == 2)
12190  {
12191  ELinkPos = 3;
12192  }
12193  if(PrefDirVector.at(LastElementNumber(52)).XLinkPos == 3)
12194  {
12195  ELinkPos = 2;
12196  }
12197  if(PrefDirVector.at(LastElementNumber(53)).ELink == -1) // because was start element
12198  {
12199  PrefDirVector.at(LastElementNumber(54)).ELink = PrefDirVector.at(LastElementNumber(55)).Link[ELinkPos];
12200  PrefDirVector.at(LastElementNumber(56)).ELinkPos = ELinkPos;
12201  PrefDirVector.at(LastElementNumber(57)).CheckCount++;
12202  PrefDirVector.at(LastElementNumber(58)).CheckCount++;
12203  }
12204  break; // no point going any further
12205  }
12206  }
12207 // set EXNumber for last PrefDir element, unless already set
12208 // won't be set if was first element or a leading point
12209  if(PrefDirVector.at(LastElementNumber(59)).EXNumber == -1)
12210  {
12211 /* The order for entries & exits is as follows (1st no = entry, 2nd = exit):-
12212  int EXArray[32][2] = {
12213  {4,6},{2,8}, //horizontal & vertical
12214  {2,4},{6,2},{8,6},{4,8}, //sharp curves
12215  {1,6},{3,8},{9,4},{7,2},{1,8},{3,4},{9,2},{7,6}, //loose curves
12216  {1,9},{3,7} //forward & reverse diagonals
12217 */
12218 
12219  if(!(PrefDirVector.at(LastElementNumber(60)).EntryExitNumber()))
12220  {
12221  throw Exception("Error in EntryExitNumber 1");
12222  }
12223  PrefDirVector.at(LastElementNumber(61)).EXGraphicPtr = PrefDirVector.at(LastElementNumber(62)).GetPrefDirGraphicPtr();
12224  PrefDirVector.at(LastElementNumber(63)).EntryDirectionGraphicPtr = PrefDirVector.at(LastElementNumber(64)).GetDirectionPrefDirGraphicPtr();
12225  PrefDirVector.at(LastElementNumber(65)).CheckCount++;
12226  }
12227 // Last PrefDir element now complete
12228 
12229 // construct remaining PrefDir elements from searchvector
12230  for(unsigned int x = 0; x < SearchVector.size(); x++)
12231  {
12232  SearchElement = SearchVector.at(x);
12233  TPrefDirElement PrefDirElement(Track->TrackElementAt(75, SearchElement.TrackVectorPosition));
12234  PrefDirElement.TrackVectorPosition = SearchElement.TrackVectorPosition;
12235  PrefDirElement.ELink = SearchElement.ELink;
12236  PrefDirElement.ELinkPos = SearchElement.ELinkPos;
12237  PrefDirElement.XLink = SearchElement.XLink;
12238  PrefDirElement.XLinkPos = SearchElement.XLinkPos;
12239 // if XLink & XLinkPos not set don't account for them in CheckCount
12240  if(PrefDirElement.XLink == -1)
12241  {
12242  PrefDirElement.CheckCount = 6; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
12243  }
12244  // & TrackVectorPosition
12245  else
12246  {
12247  PrefDirElement.CheckCount = 8; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
12248  }
12249  // XLink, XLinkPos, TrackVectorPosition
12250 
12251 // set EXNumber (can't set EXNumber if XLink not set - if finished on a leading point
12252  if(PrefDirElement.XLink != -1)
12253  {
12254  if(!(PrefDirElement.EntryExitNumber()))
12255  {
12256  throw Exception("Error in EntryExitNumber 2");
12257  }
12258  PrefDirElement.EXGraphicPtr = PrefDirElement.GetPrefDirGraphicPtr();
12259  PrefDirElement.EntryDirectionGraphicPtr = PrefDirElement.GetDirectionPrefDirGraphicPtr();
12260  PrefDirElement.CheckCount++;
12261  // all values now incorporated if not a leading point
12262  }
12263 // store PrefDir element
12264  StorePrefDirElement(2, PrefDirElement);
12265  }
12266 // Can now validate if PrefDir finished, i.e. if buffers or continuation, else validate when 'AddPrefDir' button pressed
12267  if((LastElementPtr(0)->TrackType == Buffers) || (LastElementPtr(1)->TrackType == Continuation))
12268  {
12269  if(ValidatePrefDir(2))
12270  {
12271  ;
12272  } // error messages given within function
12273 
12274  }
12276 /* drop this, check dropped from search
12277  if(PrefDirVector.size() > 200)
12278  {
12279  ShowMessage("The selected track segment is becoming too long, until it is accepted further elements can only be added one at a time");
12280  }
12281 */
12282  Utilities->CallLogPop(148);
12283 }
12284 
12285 // ---------------------------------------------------------------------------
12286 
12287 bool TOnePrefDir::EndPossible(int Caller, bool &LeadingPoints)
12288 /*
12289  Return true if selected element is valid as a PrefDir end element, i.e. isn't leading points,
12290  and PrefDir isn't one element long. Used to enable the AddPrefDirButton during PrefDir building.
12291 */
12292 {
12293  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EndPossible");
12294  LeadingPoints = false;
12295  if(PrefDirVector.empty())
12296  {
12297  Utilities->CallLogPop(1786);
12298  return(false); // should never be empty but allow for it for safety
12299  }
12300  if(PrefDirVector.size() == 1)
12301  {
12302  Utilities->CallLogPop(149);
12303  return(false); // can't end if only one element
12304  }
12305 /*
12306  if((PrefDirVector.at(LastElementNumber()).TrackType != Points) &&
12307  (PrefDirVector.at(LastElementNumber()).TrackType != Crossover))
12308  {
12309  Utilities->CallLogPop(150);
12310  return true;
12311  }
12312 */
12313 // allow for anything but leading points
12314  if((PrefDirVector.at(LastElementNumber(66)).TrackType != Points) || (PrefDirVector.at(LastElementNumber(67)).ELinkPos == 1) ||
12315  (PrefDirVector.at(LastElementNumber(71)).ELinkPos == 3))
12316  {
12317  Utilities->CallLogPop(1776);
12318  return(true);
12319  }
12320  else
12321  {
12322  LeadingPoints = true;
12323  Utilities->CallLogPop(151);
12324  return(false);
12325  }
12326 }
12327 
12328 // ---------------------------------------------------------------------------
12329 
12331 /*
12332  Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default values,
12333  and that every element is connected to the next element
12334 */
12335 {
12336  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ValidatePrefDir");
12337  int Position;
12338  AnsiString ErrorString;
12339  bool Error = false;
12340 
12341  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12342  {
12343  if(PrefDirVector.at(x).HLoc == -2000000000)
12344  {
12345  Error = true;
12346  ErrorString = "HLoc";
12347  Position = x;
12348  }
12349  if(PrefDirVector.at(x).VLoc == -2000000000)
12350  {
12351  Error = true;
12352  ErrorString = "VLoc";
12353  Position = x;
12354  }
12355  if(PrefDirVector.at(x).ELink == -1)
12356  {
12357  Error = true;
12358  ErrorString = "ELink";
12359  Position = x;
12360  }
12361  if(PrefDirVector.at(x).ELinkPos == -1)
12362  {
12363  Error = true;
12364  ErrorString = "ELinkPos";
12365  Position = x;
12366  }
12367  if(PrefDirVector.at(x).XLink == -1)
12368  {
12369  Error = true;
12370  ErrorString = "XLink";
12371  Position = x;
12372  }
12373  if(PrefDirVector.at(x).XLinkPos == -1)
12374  {
12375  Error = true;
12376  ErrorString = "XLinkPos";
12377  Position = x;
12378  }
12379  if(PrefDirVector.at(x).SpeedTag == 0)
12380  {
12381  Error = true;
12382  ErrorString = "Tag";
12383  Position = x;
12384  }
12385  if(PrefDirVector.at(x).TrackVectorPosition == -1)
12386  {
12387  Error = true;
12388  ErrorString = "TrackVectorPosition";
12389  Position = x;
12390  }
12391  if(PrefDirVector.at(x).EXNumber == -1)
12392  {
12393  Error = true;
12394  ErrorString = "EXNumber";
12395  Position = x;
12396  }
12397  if(PrefDirVector.at(x).CheckCount != 9)
12398  // HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink, ELinkPos, XLink, XLinkPos & EXNumber
12399  {
12400  Error = true;
12401  ErrorString = "CheckCount";
12402  Position = x;
12403  }
12404 // extra checks
12405  if(PrefDirVector.at(x).EXGraphicPtr == 0)
12406  {
12407  Error = true;
12408  ErrorString = "EntryGraphicPtr";
12409  Position = x;
12410  }
12411  if(PrefDirVector.at(x).EntryDirectionGraphicPtr == 0)
12412  {
12413  Error = true;
12414  ErrorString = "EntryDirectionGraphicPtr";
12415  Position = x;
12416  }
12417 // end of extra checks
12418  if(x > 0)
12419  {
12420  if(PrefDirVector.at(x - 1).Conn[PrefDirVector.at(x - 1).XLinkPos] != PrefDirVector.at(x).TrackVectorPosition)
12421  {
12422  Error = true;
12423  ErrorString = "Last XLink not connected to this element";
12424  Position = x;
12425  }
12426  }
12427  }
12428  if(Error)
12429  {
12430  throw Exception("Error at " + AnsiString(Position) + " " + ErrorString);
12431  }
12432  else
12433  {
12434  Utilities->CallLogPop(153);
12435  return(true);
12436  }
12437 }
12438 
12439 // ---------------------------------------------------------------------------
12440 
12441 bool TOnePrefDir::GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
12442 /*
12443  This is only called during PrefDir build or distance setting. It truncates at & including the first element in the PrefDir vector
12444  that matches H & V. After the truncate the final element of the remaining PrefDir has its data members reset
12445  to the same defaults as would be the case if the PrefDir had been built up to that point - i.e. for first element
12446  or a leading point.
12447 */
12448 {
12449  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
12450  for(unsigned int x = 0; x < (PrefDirVector.size()); x++)
12451  {
12452  if((PrefDirVector.at(x).HLoc == HLoc) && (PrefDirVector.at(x).VLoc == VLoc))
12453  {
12454  for(int PrefDirVecPos = (PrefDirVector.size() - 1); PrefDirVecPos >= (int)x; PrefDirVecPos--) // has to be int or will underflow at x==0
12455  {
12456  ErasePrefDirElementAt(1, PrefDirVecPos);
12457  }
12458  if(PrefDirVector.size() == 0)
12459  {
12460  Utilities->CallLogPop(154);
12461  return(true);
12462  }
12463  if(PrefDirVector.size() == 1)
12464  {
12465  PrefDirVector.at(x - 1).ELinkPos = -1;
12466  PrefDirVector.at(x - 1).ELink = -1;
12467  PrefDirVector.at(x - 1).XLinkPos = -1;
12468  PrefDirVector.at(x - 1).XLink = -1;
12469  PrefDirVector.at(x - 1).EXNumber = -1;
12470  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
12471  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
12472  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 5;
12473  Utilities->CallLogPop(155);
12474  return(true);
12475  }
12476  // here with truncate element not first element, so ELink & ELinkPos set
12477  // unset XLink & Pos if a leading point
12478  if(PrefDirVector.at(x - 1).Config[PrefDirVector.at(x - 1).ELinkPos] == Lead)
12479  {
12480  PrefDirVector.at(x - 1).XLinkPos = -1;
12481  PrefDirVector.at(x - 1).XLink = -1;
12482  PrefDirVector.at(x - 1).EXNumber = -1;
12483  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
12484  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
12485  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 3;
12486  Utilities->CallLogPop(156);
12487  return(true);
12488  }
12489  Utilities->CallLogPop(157);
12490  return(true);
12491  }
12492  }
12493  Utilities->CallLogPop(158);
12494  return(false);
12495 }
12496 
12497 // ---------------------------------------------------------------------------
12498 
12499 void TOnePrefDir::PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp)
12500 const // PrefDirRoute = PrefDircall or routecall for PrefDir or route; true for BuildingPrefDir
12501 /*
12502  PrefDir and route track marker, including direction markers. Function used for both PrefDirs (PrefDirRoute == PrefDirCall) and routes
12503  (PrefDirRoute == RouteCall). The graphics for marker colours and direction are already stored in all PrefDirElements in
12504  TOnePrefDir and TOneRoute, and this function is called to display them, all in the case of a PrefDir, but for a route only the
12505  first and last elements have direction markers. No markers are displayed if a train is present on an element. Also no
12506  display if EXGraphicPtr not set. If building a PrefDir (BuildingPrefDir true) then the start and end rectangles are also
12507  displayed.
12508 */
12509 {
12510  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PrefDirMarker," + AnsiString(PrefDirRoute) + "," +
12511  AnsiString((short)BuildingPrefDir));
12512  int HPos, VPos;
12513 
12514  if(PrefDirSize() == 0)
12515  {
12516  Utilities->CallLogPop(159);
12517  return;
12518  }
12519  for(unsigned int x = 0; x < PrefDirSize(); x++)
12520  {
12521  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
12522 // if(Track->TrackElementAt(76, TempPrefDirElement.TrackVectorPosition).TrainIDOnElement > -1) continue;
12523 // don't plot route element if train present - dropped above as train departing only replotted the part of the route
12524 // that the train was on. Ensure though that whenever plot a route replot trains after else route will overwrite train
12525  // without the above, if route replotted in ClearandRebuildRailway when train is straddling 3 elements
12526  // and before the next train update, then the route element corresponding to the LagElement will be plotted,
12527  // only the front half of which will be overplotted by the back of the train, then when the train is
12528  // updated the route image will remain plotted and stay on screen until a later ClearandRebuildRailway
12529  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
12530  {
12531  Disp->PlotOutput(12, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EXGraphicPtr);
12532  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == PrefDirCall)) // PrefDir
12533  {
12534  Disp->PlotOutput(13, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12535  }
12536  else if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == RouteCall) && PrefDirSize() > 1)
12537  // Route, no direction if a single element
12538  {
12539  if(x == 0)
12540  {
12541  Disp->PlotOutput(14, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12542  }
12543  if(x == (PrefDirSize() - 1))
12544  {
12545  Disp->PlotOutput(15, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12546  }
12547  }
12548  }
12549  }
12550 
12551 // set start & end element colours if building a PrefDir
12552  if((PrefDirRoute == PrefDirCall) && BuildingPrefDir)
12553  {
12554  HPos = GetFixedPrefDirElementAt(4, 0).HLoc * 16;
12555  VPos = GetFixedPrefDirElementAt(5, 0).VLoc * 16;
12556  Disp->Rectangle(1, HPos, VPos, clB0G0R5, 2, 2); // medium red rectangle
12557  // set last element colour
12558  if(PrefDirSize() > 1)
12559  {
12560  unsigned int LatestPos = PrefDirSize() - 1;
12561  HPos = GetFixedPrefDirElementAt(6, LatestPos).HLoc * 16;
12562  VPos = GetFixedPrefDirElementAt(7, LatestPos).VLoc * 16;
12563  Disp->Rectangle(2, HPos, VPos, clB5G0R0, 4, 2); // smaller blue rectangle
12564  }
12565  }
12566  Disp->Update();
12567  Utilities->CallLogPop(160);
12568 }
12569 
12570 // ---------------------------------------------------------------------------
12571 
12573 /*
12574  Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green for bidirectional
12575  Colours taken from the route colours. Plot red first so green overwrites for bidirectional points.
12576 */
12577 {
12578  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EveryPrefDirMarker");
12579  if(PrefDirSize() == 0)
12580  {
12581  Utilities->CallLogPop(1547);
12582  return;
12583  }
12584  int H, V, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
12585  bool FoundFlag;
12587  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
12588 
12589  while(MMIT != PrefDir4MultiMap.end())
12590  {
12591  H = MMIT->first.first;
12592  V = MMIT->first.second;
12593  GetVectorPositionsFromPrefDir4MultiMap(6, H, V, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12594  // always found in order, any missing have PrefDirPosx == -1
12595  if(PrefDirPos0 > -1)
12596  {
12597  PrefDirElement0 = GetFixedPrefDirElementAt(170, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
12598  }
12599  if(PrefDirPos1 > -1)
12600  {
12601  PrefDirElement1 = GetFixedPrefDirElementAt(171, PrefDirPos1);
12602  }
12603  if(PrefDirPos2 > -1)
12604  {
12605  PrefDirElement2 = GetFixedPrefDirElementAt(172, PrefDirPos2);
12606  }
12607  if(PrefDirPos3 > -1)
12608  {
12609  PrefDirElement3 = GetFixedPrefDirElementAt(173, PrefDirPos3);
12610  }
12611  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
12612  {
12613  // need to plot all 4 in order to obtain all the direction graphics
12614  Disp->PlotOutput(77, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12615  Disp->PlotOutput(78, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12616  Disp->PlotOutput(79, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12617  Disp->PlotOutput(80, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12618  Disp->PlotOutput(81, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12619  Disp->PlotOutput(82, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12620  Disp->PlotOutput(83, (H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
12621  Disp->PlotOutput(84, (H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
12622  MMIT++;
12623  MMIT++;
12624  MMIT++;
12625  MMIT++;
12626  }
12627  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
12628  {
12629  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
12630  {
12631  // 0 & 1 constitute the bidirectional PrefDir
12632  Disp->PlotOutput(89, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
12633  Disp->PlotOutput(90, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
12634  Disp->PlotOutput(85, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12635  Disp->PlotOutput(86, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12636  Disp->PlotOutput(87, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12637  Disp->PlotOutput(88, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12638  MMIT++;
12639  MMIT++;
12640  MMIT++;
12641  }
12642  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
12643  {
12644  // 0 & 2 constitute the bidirectional PrefDir
12645  Disp->PlotOutput(95, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
12646  Disp->PlotOutput(96, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
12647  Disp->PlotOutput(91, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12648  Disp->PlotOutput(92, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12649  Disp->PlotOutput(93, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12650  Disp->PlotOutput(94, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12651  MMIT++;
12652  MMIT++;
12653  MMIT++;
12654  }
12655  else
12656  {
12657  // 1 & 2 constitute the bidirectional PrefDir
12658  Disp->PlotOutput(101, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12659  Disp->PlotOutput(102, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12660  Disp->PlotOutput(97, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12661  Disp->PlotOutput(98, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12662  Disp->PlotOutput(99, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12663  Disp->PlotOutput(100, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12664  MMIT++;
12665  MMIT++;
12666  MMIT++;
12667  }
12668  }
12669  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
12670  {
12671  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
12672  {
12673  // 0 & 1 constitute the bidirectional PrefDir
12674  Disp->PlotOutput(103, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12675  Disp->PlotOutput(104, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12676  Disp->PlotOutput(105, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12677  Disp->PlotOutput(106, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12678  MMIT++;
12679  MMIT++;
12680  }
12681  else
12682  {
12683  // 2 unidirectional PrefDirs
12684  Disp->PlotOutput(107, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12685  Disp->PlotOutput(108, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12686  Disp->PlotOutput(109, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
12687  Disp->PlotOutput(110, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
12688  MMIT++;
12689  MMIT++;
12690  }
12691  }
12692  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
12693  {
12694  Disp->PlotOutput(111, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12695  Disp->PlotOutput(112, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12696  MMIT++;
12697  }
12698  }
12699  Disp->Update();
12700  Utilities->CallLogPop(1548);
12701 }
12702 
12703 // ---------------------------------------------------------------------------
12704 
12705 void TOnePrefDir::LoadOldPrefDir(int Caller, std::ifstream &VecFile)
12706 {
12707  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOldPrefDir");
12708  int TempInt;
12709 
12710  ClearPrefDir();
12711  int NumberOfPrefDirElements = 0;
12712 
12713  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12714  for(int x = 0; x < NumberOfPrefDirElements; x++)
12715  {
12716  VecFile >> TempInt; // TrackVectorPosition
12717  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(714, TempInt));
12718  LoadPrefDirElement.TrackVectorPosition = TempInt;
12719  VecFile >> TempInt;
12720  LoadPrefDirElement.ELink = TempInt;
12721  VecFile >> TempInt;
12722  LoadPrefDirElement.ELinkPos = TempInt;
12723  VecFile >> TempInt;
12724  LoadPrefDirElement.XLink = TempInt;
12725  VecFile >> TempInt;
12726  LoadPrefDirElement.XLinkPos = TempInt;
12727  VecFile >> TempInt;
12728  LoadPrefDirElement.EXNumber = TempInt;
12729  VecFile >> TempInt;
12730  LoadPrefDirElement.CheckCount = TempInt;
12731  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
12732  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
12733  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
12734  if(!(LoadPrefDirElement.IsARoute))
12735  {
12736  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
12737  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
12738  }
12739  else
12740  {
12741  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
12742  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
12743  LoadPrefDirElement.PrefDirRoute);
12744  }
12745  StorePrefDirElement(5, LoadPrefDirElement);
12746  Utilities->LoadFileString(VecFile); // marker
12747  }
12749  Utilities->CallLogPop(161);
12750 }
12751 
12752 // ---------------------------------------------------------------------------
12753 
12754 void TOnePrefDir::LoadPrefDir(int Caller, std::ifstream &VecFile)
12755 {
12756  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPrefDir");
12757  int TempInt;
12758 
12759  ClearPrefDir();
12760  int NumberOfPrefDirElements = 0;
12761 
12762  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12763  for(int x = 0; x < NumberOfPrefDirElements; x++)
12764  {
12765  VecFile >> TempInt; // PrefDirVectorPosition, not used in load
12766  VecFile >> TempInt; // TrackVectorPosition
12767  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(781, TempInt)); //Loads all basic TrackElement values incl HLoc, VLoc & SpeedTag
12768  LoadPrefDirElement.TrackVectorPosition = TempInt;
12769  VecFile >> TempInt;
12770  LoadPrefDirElement.ELink = TempInt;
12771  VecFile >> TempInt;
12772  LoadPrefDirElement.ELinkPos = TempInt;
12773  VecFile >> TempInt;
12774  LoadPrefDirElement.XLink = TempInt;
12775  VecFile >> TempInt;
12776  LoadPrefDirElement.XLinkPos = TempInt;
12777  VecFile >> TempInt;
12778  LoadPrefDirElement.EXNumber = TempInt;
12779  VecFile >> TempInt;
12780  LoadPrefDirElement.CheckCount = TempInt;
12781  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
12782  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
12783  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
12784  if(!(LoadPrefDirElement.IsARoute))
12785  {
12786  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
12787  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
12788  }
12789  else
12790  {
12791  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
12792  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
12793  LoadPrefDirElement.PrefDirRoute);
12794  }
12795  StorePrefDirElement(0, LoadPrefDirElement);
12796  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // marker
12797  }
12799  Utilities->CallLogPop(1509);
12800 }
12801 
12802 // ---------------------------------------------------------------------------
12803 
12804 bool TOnePrefDir::CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile) // returns false if no more PrefDirs to check
12805 /*
12806  Called before PrefDir loading as part of the FileIntegrityCheck function, in case there is an error in the
12807  file. Very similar to LoadPrefDir but with value checks instead of storage in PrefDirVector.
12808 */
12809 {
12810  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckOnePrefDir");
12811  int TempInt;
12812  int NumberOfPrefDirElements = 0;
12813 
12814  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12815  if((NumberOfPrefDirElements < 0) || (NumberOfPrefDirElements > 1000000))
12816  {
12817  Utilities->CallLogPop(1152);
12818  return(false);
12819  }
12820  for(int x = 0; x < NumberOfPrefDirElements; x++)
12821  {
12822  if(!Utilities->CheckFileInt(VecFile, x, x)) // vector number
12823  {
12824  Utilities->CallLogPop(1766);
12825  return(false);
12826  }
12827  VecFile >> TempInt;
12828  if((TempInt < 0) || (TempInt >= NumberOfActiveElements)) // TrackVectorPosition
12829  {
12830  Utilities->CallLogPop(163);
12831  return(false);
12832  }
12833  VecFile >> TempInt;
12834  if((TempInt < -1) || (TempInt > 9)) // ELink
12835  {
12836  Utilities->CallLogPop(162);
12837  return(false);
12838  }
12839  VecFile >> TempInt;
12840  if((TempInt < -1) || (TempInt > 3)) // ELinkPos
12841  {
12842  Utilities->CallLogPop(164);
12843  return(false);
12844  }
12845  VecFile >> TempInt;
12846  if((TempInt < -1) || (TempInt > 9)) // XLink
12847  {
12848  Utilities->CallLogPop(165);
12849  return(false);
12850  }
12851  VecFile >> TempInt;
12852  if((TempInt < -1) || (TempInt > 3)) // XLinkPos
12853  {
12854  Utilities->CallLogPop(166);
12855  return(false);
12856  }
12857  VecFile >> TempInt;
12858  if((TempInt < -1) || (TempInt > 27)) // EXNumber
12859  {
12860  Utilities->CallLogPop(167);
12861  return(false);
12862  }
12863  VecFile >> TempInt;
12864  if(TempInt != 9) // CheckCount - reduced to 11 after NextPrefDirElement dropped &
12865  // to 9 after End & Stop dropped. Leaving HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink,
12866  // ELinkPos, XLink, XLinkPos & EXNumber
12867  {
12868  Utilities->CallLogPop(168);
12869  return(false);
12870  }
12871  VecFile >> TempInt;
12872  if((TempInt != 0) && (TempInt != 1)) // RouteElement
12873  {
12874  Utilities->CallLogPop(1147);
12875  return(false);
12876  }
12877  VecFile >> TempInt;
12878  if((TempInt != 0) && (TempInt != 1)) // AutoSignals
12879  {
12880  Utilities->CallLogPop(1510);
12881  return(false);
12882  }
12883  VecFile >> TempInt;
12884  if((TempInt != 0) && (TempInt != 1)) // PrefDirRoute
12885  {
12886  Utilities->CallLogPop(1148);
12887  return(false);
12888  }
12889  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // marker
12890  {
12891  Utilities->CallLogPop(1700);
12892  return(false);
12893  }
12894  }
12895  Utilities->CallLogPop(169);
12896  return(true);
12897 }
12898 
12899 // ---------------------------------------------------------------------------
12900 
12901 void TOnePrefDir::SavePrefDirVector(int Caller, std::ofstream &VecFile)
12902 {
12903  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePrefDir");
12904  int NumberOfPrefDirElements = PrefDirVector.size();
12905 
12906  Utilities->SaveFileInt(VecFile, NumberOfPrefDirElements);
12907  for(int y = 0; y < NumberOfPrefDirElements; y++)
12908  {
12909  VecFile << y << '\n'; // extra
12910  VecFile << PrefDirVector.at(y).TrackVectorPosition << '\n'; //When reloaded values for HLoc, VLoc & SpeedTag are derived from the TrackElement at TrackVectorPosition
12911  VecFile << PrefDirVector.at(y).ELink << '\n'; //so all 9 critical values are set
12912  VecFile << PrefDirVector.at(y).ELinkPos << '\n';
12913  VecFile << PrefDirVector.at(y).XLink << '\n';
12914  VecFile << PrefDirVector.at(y).XLinkPos << '\n';
12915  VecFile << PrefDirVector.at(y).EXNumber << '\n';
12916  VecFile << PrefDirVector.at(y).CheckCount << '\n';
12917  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).IsARoute);
12918  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).AutoSignals);
12919  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).PrefDirRoute);
12920  if(y == (NumberOfPrefDirElements - 1)) // last element, write a longer delimiter
12921  {
12922  VecFile << "************" << '\0' << '\n'; // marker
12923  }
12924  else
12925  {
12926  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
12927  }
12928  }
12929  Utilities->CallLogPop(170);
12930 }
12931 
12932 // ---------------------------------------------------------------------------
12933 
12934 void TOnePrefDir::SaveSearchVector(int Caller, std::ofstream &VecFile)
12935 {
12936  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSearchVector");
12937  int NumberOfSearchElements = SearchVector.size();
12938 
12939  Utilities->SaveFileInt(VecFile, NumberOfSearchElements);
12940  for(int y = 0; y < NumberOfSearchElements; y++)
12941  {
12942  VecFile << y << '\n'; // extra
12943  VecFile << SearchVector.at(y).TrackVectorPosition << '\n';
12944  VecFile << SearchVector.at(y).ELink << '\n';
12945  VecFile << SearchVector.at(y).ELinkPos << '\n';
12946  VecFile << SearchVector.at(y).XLink << '\n';
12947  VecFile << SearchVector.at(y).XLinkPos << '\n';
12948  VecFile << SearchVector.at(y).EXNumber << '\n';
12949  VecFile << SearchVector.at(y).CheckCount << '\n';
12950  Utilities->SaveFileBool(VecFile, SearchVector.at(y).IsARoute);
12951  Utilities->SaveFileBool(VecFile, SearchVector.at(y).AutoSignals);
12952  Utilities->SaveFileBool(VecFile, SearchVector.at(y).PrefDirRoute);
12953  if(y == (NumberOfSearchElements - 1)) // last element, write a longer delimiter
12954  {
12955  VecFile << "************" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
12956  }
12957  else
12958  {
12959  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
12960  }
12961  }
12962  Utilities->CallLogPop(1847);
12963 }
12964 
12965 // ---------------------------------------------------------------------------
12966 
12967 void TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
12968 /*
12969  Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails
12970  erasing up to four elements (2 directions and 2 tracks for 4-entry elements).
12971 */
12972 {
12973  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseFromPrefDirVectorAnd4MultiMap," + AnsiString(HLoc) + "," +
12974  AnsiString(VLoc));
12975  int VecPos = GetOnePrefDirPosition(1, HLoc, VLoc);
12976 
12977  if(VecPos > -1)
12978  {
12979  ErasePrefDirElementAt(2, VecPos); // max of 4 to be erased
12980  }
12981  else
12982  {
12983  Utilities->CallLogPop(171);
12984  return;
12985  }
12986  VecPos = GetOnePrefDirPosition(2, HLoc, VLoc);
12987  if(VecPos > -1)
12988  {
12989  ErasePrefDirElementAt(3, VecPos);
12990  }
12991  else
12992  {
12993  Utilities->CallLogPop(172);
12994  return;
12995  }
12996  VecPos = GetOnePrefDirPosition(3, HLoc, VLoc);
12997  if(VecPos > -1)
12998  {
12999  ErasePrefDirElementAt(4, VecPos);
13000  }
13001  else
13002  {
13003  Utilities->CallLogPop(173);
13004  return;
13005  }
13006  VecPos = GetOnePrefDirPosition(4, HLoc, VLoc);
13007  if(VecPos > -1)
13008  {
13009  ErasePrefDirElementAt(5, VecPos);
13010  }
13011  else
13012  {
13013  Utilities->CallLogPop(174);
13014  return;
13015  }
13016  Utilities->CallLogPop(175);
13017 }
13018 
13019 // ---------------------------------------------------------------------------
13020 /*
13021  void TOnePrefDir::EraseCorruptedElementsAfterTrackBuild()//Delete any PrefDir elements that are no longer valid
13022  //Not needed after new TrackErase (now EraseTrackElement), where blank elements aren't used
13023 
13024  When track is rebuilt any elements that are dispensed with aren't erased immediately, a blank element is put
13025  in their place so that existing linkages will be preserved. At this stage this function is called to remove
13026  any elements in PrefDirVector that correspond directly to blank track elements or that are connected to blank track
13027  elements. Finally the track is reconnected using Track->TryToConnectTrack (if won't connect then returns to
13028  AddTrackStage build mode for corrections to be made) and then EveryPrefDir->RebuildPrefDirVector() called to reset
13029  PrefDirVector to correspond to the new track layout.
13030 
13031  {
13032  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EraseCorruptedElementsAfterTrackBuild");
13033  if(PrefDirSize() == 0)
13034  {
13035  Utilities->CallLogPop(176);
13036  return;
13037  }
13038  for(int x=(PrefDirVector.size()-1);x>=0;x--)
13039  {
13040  int TV = PrefDirVector.at(x).TrackVectorPosition;
13041  int ConnELink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).ELinkPos];
13042  int ConnXLink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).XLinkPos];
13043  if(Track->BlankElementAt(0, TV))
13044  {
13045  ErasePrefDirElementAt(6, x);
13046  }
13047  //if was a blankelement at x then ConnELink and ConnXLink both -1
13048  else if((ConnELink > -1) && (Track->BlankElementAt(1, ConnELink)))
13049  {
13050  ErasePrefDirElementAt(7, x);
13051  }
13052  //if both ConnELink and ConnXLink correspond to blank elements then OK, element only
13053  //needs to be erased once, but if don't use 'else' then will erase two elements
13054  //since 'x' will correspond to the element after the first erased element
13055  else if((ConnXLink > -1) && (Track->BlankElementAt(2, ConnXLink)))
13056  {
13057  ErasePrefDirElementAt(8, x);
13058  }
13059  }
13060  Utilities->CallLogPop(177);
13061  }
13062 */
13063 // ---------------------------------------------------------------------------
13064 
13065 void TOnePrefDir::ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
13066 /*
13067  This is used to add InputPrefDir's PrefDirVector to TOnePrefDir's PrefDirVector except where it already
13068  exists in TOnePrefDir. In practice it adds ConstructPrefDir to EveryPrefDir.
13069 */
13070 {
13071  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConsolidatePrefDirs");
13072  bool AlreadyPresent, FoundFlag;
13073  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13074 
13075  for(unsigned int x = 0; x < InputPrefDir->PrefDirSize(); x++)
13076  {
13077  TPrefDirElement TempElement = InputPrefDir->PrefDirVector.at(x);
13078  GetVectorPositionsFromPrefDir4MultiMap(1, TempElement.HLoc, TempElement.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13079  AlreadyPresent = false;
13080  if(FoundFlag)
13081  {
13082  if((PrefDirPos0 > -1) && (TempElement == GetFixedPrefDirElementAt(8, PrefDirPos0)))
13083  {
13084  AlreadyPresent = true;
13085  }
13086  if((PrefDirPos1 > -1) && (TempElement == GetFixedPrefDirElementAt(9, PrefDirPos1)))
13087  {
13088  AlreadyPresent = true;
13089  }
13090  if((PrefDirPos2 > -1) && (TempElement == GetFixedPrefDirElementAt(10, PrefDirPos2)))
13091  {
13092  AlreadyPresent = true;
13093  }
13094  if((PrefDirPos3 > -1) && (TempElement == GetFixedPrefDirElementAt(11, PrefDirPos3)))
13095  {
13096  AlreadyPresent = true;
13097  }
13098  }
13099  if(!AlreadyPresent)
13100  {
13101  StorePrefDirElement(4, TempElement);
13102  }
13103  }
13105  Utilities->CallLogPop(178);
13106 }
13107 /* earlier brute force search
13108  for(unsigned int x = 0;x<InputPrefDir->PrefDirSize();x++)
13109  {
13110  TPrefDirElement TempElement = InputPrefDir->GetFixedPrefDirElementAt(12, x);
13111  bool AlreadyPresent = false;
13112  for(unsigned int y = 0;y<PrefDirSize();y++)
13113  {
13114  if(TempElement == GetFixedPrefDirElementAt(13, y)) AlreadyPresent = true;
13115  }
13116  if(!AlreadyPresent) StorePrefDirElement(, TempElement);
13117  }
13118 */
13119 
13120 // ---------------------------------------------------------------------------
13121 
13123 /*
13124  Rebuild from Trackmap, doesn't affect PrefDir4MultiMap.
13125  After a track build, but before the track is reconnected, all invalid PrefDir elements in TOnePrefDir
13126  (i.e. in EveryPrefDir) are erased. Hence at that stage all the PrefDir elements are valid and correspond to
13127  the track elements at relevant H & V positions. However, after the track is reconnected, the TrackVector
13128  positions are likely to have changed, so this function is called to reset all the necessary connections and
13129  TrackVector positions. To be on the safe side all the TrackElement values that are additional to
13130  TFixedTrackPiece (apart from TrainIDs, these only present during operation) are reset, though the others
13131  shouldn't have changed.
13132 */
13133 {
13134  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildPrefDirVector");
13135  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
13136  {
13137  bool FoundFlag;
13138  int VecPos = Track->GetVectorPositionFromTrackMap(10, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
13139  if(FoundFlag)
13140  {
13141  PrefDirVector.at(x).TrackVectorPosition = VecPos;
13142  PrefDirVector.at(x).LocationName = Track->TrackElementAt(78, VecPos).LocationName;
13143  PrefDirVector.at(x).ActiveTrackElementName = Track->TrackElementAt(79, VecPos).ActiveTrackElementName;
13144  PrefDirVector.at(x).ElementID = Track->TrackElementAt(80, VecPos).ElementID;
13145  PrefDirVector.at(x).Attribute = Track->TrackElementAt(81, VecPos).Attribute;
13146  for(unsigned int z = 0; z < 4; z++)
13147  {
13148  PrefDirVector.at(x).Conn[z] = Track->TrackElementAt(82, VecPos).Conn[z];
13149  PrefDirVector.at(x).ConnLinkPos[z] = Track->TrackElementAt(83, VecPos).ConnLinkPos[z];
13150  }
13151  }
13152  else
13153  {
13154  throw Exception("Error in RebuildPrefDirVector - PrefDirVector is unsafe");
13155  }
13156  }
13157  Utilities->CallLogPop(179);
13158 }
13159 
13160 // ---------------------------------------------------------------------------
13161 
13163 /*
13164  Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefDir & PrefDir4MultiMap.
13165 */
13166 {
13167  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVector");
13168  bool DiscrepancyFound = false;
13169 
13170  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
13171  {
13172  bool FoundFlag;
13173  int VecPos = Track->GetVectorPositionFromTrackMap(39, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
13174  if(FoundFlag)
13175  {
13176  TPrefDirElement PE = PrefDirVector.at(x);
13177  if(PE.TrackVectorPosition != VecPos)
13178  {
13179  DiscrepancyFound = true;
13180  break;
13181  }
13182  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
13183  {
13184  DiscrepancyFound = true;
13185  break;
13186  }
13187  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
13188  {
13189  DiscrepancyFound = true;
13190  break;
13191  }
13192  if(PE.ELink != Track->TrackElementAt(710, VecPos).Link[PE.GetELinkPos()])
13193  {
13194  DiscrepancyFound = true;
13195  break;
13196  }
13197  if(PE.XLink != Track->TrackElementAt(711, VecPos).Link[PE.GetXLinkPos()])
13198  {
13199  DiscrepancyFound = true;
13200  break;
13201  }
13202  }
13203  else
13204  {
13205  DiscrepancyFound = true;
13206  }
13207  }
13208  if(DiscrepancyFound)
13209  {
13210  ShowMessage("Discrepancies found in the preferred direction file, preferred directions will be cleared");
13211  ClearPrefDir(); // also clears multimap
13212  }
13213  Utilities->CallLogPop(1436);
13214 }
13215 
13216 // ---------------------------------------------------------------------------
13217 
13219 /*
13220  Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4MultiMap.
13221  return true for OK
13222 */
13223 {
13224  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVectorNoMessage");
13225  bool DiscrepancyFound = false;
13226 
13227  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
13228  {
13229  bool FoundFlag;
13230  int VecPos = Track->GetVectorPositionFromTrackMap(36, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
13231  if(FoundFlag)
13232  {
13233  TPrefDirElement PE = PrefDirVector.at(x);
13234  if(PE.TrackVectorPosition != VecPos)
13235  {
13236  DiscrepancyFound = true;
13237  }
13238  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
13239  {
13240  DiscrepancyFound = true;
13241  break;
13242  }
13243  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
13244  {
13245  DiscrepancyFound = true;
13246  break;
13247  }
13248  if(PE.ELink != Track->TrackElementAt(715, VecPos).Link[PE.GetELinkPos()])
13249  {
13250  DiscrepancyFound = true;
13251  break;
13252  }
13253  if(PE.XLink != Track->TrackElementAt(716, VecPos).Link[PE.GetXLinkPos()])
13254  {
13255  DiscrepancyFound = true;
13256  break;
13257  }
13258  }
13259  else
13260  {
13261  DiscrepancyFound = true;
13262  }
13263  }
13264  Utilities->CallLogPop(1512);
13265  return(!DiscrepancyFound);
13266 }
13267 
13268 // ---------------------------------------------------------------------------
13269 
13270 void TOnePrefDir::CheckPrefDir4MultiMap(int Caller) // test
13271 /*
13272  Test function to check correspondence between PrefDirVector and PrefDir4MultiMap for each element in
13273  turn and for the overall sizes.
13274 */
13275 {
13276  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDir4MultiMap");
13277  bool FoundFlag = false;
13278  int PrefDir0, PrefDir1, PrefDir2, PrefDir3;
13279 
13280  for(unsigned int a = 0; a < PrefDirVector.size(); a++)
13281  {
13282  TPrefDirElement CheckElement = PrefDirVector.at(a);
13283  GetVectorPositionsFromPrefDir4MultiMap(2, CheckElement.HLoc, CheckElement.VLoc, FoundFlag, PrefDir0, PrefDir1, PrefDir2, PrefDir3);
13284  if(!FoundFlag)
13285  {
13286  throw Exception("CheckPrefDir4MultiMap Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
13287  " in PrefDir4MultiMap, Caller=" + (AnsiString)Caller);
13288  }
13289  if((PrefDir0 != (int)a) && (PrefDir1 != (int)a) && (PrefDir2 != (int)a) && (PrefDir3 != (int)a))
13290  {
13291  throw Exception("CheckPrefDir4MultiMap Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
13292  (AnsiString)CheckElement.VLoc + " Map values=" + (AnsiString)PrefDir0 + ", " + (AnsiString)PrefDir1 + ", " + (AnsiString)PrefDir2 + ", " +
13293  (AnsiString)PrefDir3 + " PrefDirVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
13294  }
13295  }
13296  if(PrefDirVector.size() != PrefDir4MultiMap.size())
13297  {
13298  throw Exception("CheckPrefDir4MultiMap Error - Map Size=" + (AnsiString)PrefDirVector.size() + " PrefDirVectorSize=" + (AnsiString)PrefDirVector.size()
13299  + " Caller=" + (AnsiString)Caller);
13300  }
13301  Utilities->CallLogPop(180);
13302 }
13303 
13304 // ---------------------------------------------------------------------------
13305 
13306 void TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2,
13307  int &PrefDirPos3)
13308 /*
13309  There are up to four elements at each H & V position in the PrefDirVector - two directions per track, and up to
13310  two tracks for 4-entry elements. This function retrieves all elements that are present at a given H & V
13311  position. FoundFlag indicates whether any or none have been found, and PrefDirPos0, 1, 2 & 3 contain
13312  the PrefDirVector positions, or -1 if not present. The elements are always found in order, such that
13313  if there is only one it will be in PrefDirPos0, if two they will be in PrefDirPos0 and PrefDirPos1 and so on.
13314 */
13315 {
13316  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromPrefDir4MultiMap," + AnsiString(HLoc) + "," +
13317  AnsiString(VLoc));
13318  THVPair PrefDirMapKeyPair;
13319 
13320  PrefDirPos0 = -1;
13321  PrefDirPos1 = -1;
13322  PrefDirPos2 = -1;
13323  PrefDirPos3 = -1;
13324  FoundFlag = false;
13325  PrefDirMapKeyPair.first = HLoc;
13326  PrefDirMapKeyPair.second = VLoc;
13327  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13328 
13329  ItPair = PrefDir4MultiMap.equal_range(PrefDirMapKeyPair);
13330  if(ItPair.first == ItPair.second) //none found
13331  {
13332  Utilities->CallLogPop(181);
13333  return;
13334  }
13335  else
13336  {
13337  FoundFlag = true;
13338  PrefDirPos0 = ItPair.first->second;
13339  ItPair.first++;
13340  if(ItPair.first == ItPair.second)
13341  {
13342  Utilities->CallLogPop(182); //only one found
13343  return;
13344  }
13345  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13346  {
13347  PrefDirPos1 = ItPair.first->second;
13348  }
13349  ItPair.first++;
13350  if(ItPair.first == ItPair.second)
13351  {
13352  Utilities->CallLogPop(183); //2 found
13353  return;
13354  }
13355  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13356  {
13357  PrefDirPos2 = ItPair.first->second;
13358  }
13359  ItPair.first++;
13360  if(ItPair.first == ItPair.second)
13361  {
13362  Utilities->CallLogPop(184); //3 found
13363  return;
13364  }
13365  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13366  {
13367  PrefDirPos3 = ItPair.first->second; //4 found
13368  }
13369  }
13370  Utilities->CallLogPop(185);
13371 }
13372 
13373 // ---------------------------------------------------------------------------
13374 
13375 bool TOnePrefDir::FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
13376 { //not used after modified the pref dir checking function at v2.13.0
13377  // Finds a pref dir element that links to another element at given vector number and link number & position, returns true if found with linked
13378  // vector number, true if buffer or continuation with link at blank end & linked vector number = -1, or false if not found with vector number == -1
13379  try
13380  {
13381  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindLinkingPrefDir," + AnsiString(PrefDirVectorNumber)
13382  + "," + AnsiString(LinkNumberPos));
13383  bool FoundFlag;
13384  int PD0, PD1, PD2, PD3;
13385  if(PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos] > -1)
13386  {
13387  GetVectorPositionsFromPrefDir4MultiMap(14, Track->TrackElementAt(1021, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).HLoc,
13388  Track->TrackElementAt(1022, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).VLoc, FoundFlag,
13389  PD0, PD1, PD2, PD3);
13390  if(!FoundFlag)
13391  {
13392  Utilities->CallLogPop(2282);
13393  return(false);
13394  }
13395  if((PrefDirVector.at(PrefDirVectorNumber).TrackType == GapJump) && (LinkNumberPos == 0)) //0 is the gap position
13396  {
13397  if(PD0 > -1)
13398  {
13399  if(PrefDirVector.at(PD0).TrackType == GapJump) //links to a gap and there is a pref dir set on it, doesn't matter about the link position
13400  {
13401  LinkedPrefDirVectorNumber = PD0;
13402  Utilities->CallLogPop(2283);
13403  return(true);
13404  }
13405  }
13406  if(PD1 > -1)
13407  {
13408  if(PrefDirVector.at(PD1).TrackType == GapJump) //can only be PD0 or PD1 for a gap
13409  {
13410  LinkedPrefDirVectorNumber = PD1;
13411  Utilities->CallLogPop(2284);
13412  return(true);
13413  }
13414  }
13415  }
13416  if(PD0 > -1)
13417  {
13418  if((PrefDirVector.at(PD0).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD0).XLink == (10 - LinkNumber)))
13419  {
13420  LinkedPrefDirVectorNumber = PD0;
13421  Utilities->CallLogPop(2285);
13422  return(true);
13423  }
13424  }
13425  if(PD1 > -1)
13426  {
13427  if((PrefDirVector.at(PD1).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD1).XLink == (10 - LinkNumber)))
13428  {
13429  LinkedPrefDirVectorNumber = PD1;
13430  Utilities->CallLogPop(2286);
13431  return(true);
13432  }
13433  }
13434  if(PD2 > -1)
13435  {
13436  if((PrefDirVector.at(PD2).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD2).XLink == (10 - LinkNumber)))
13437  {
13438  LinkedPrefDirVectorNumber = PD2;
13439  Utilities->CallLogPop(2287);
13440  return(true);
13441  }
13442  }
13443  if(PD3 > -1)
13444  {
13445  if((PrefDirVector.at(PD3).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD3).XLink == (10 - LinkNumber)))
13446  {
13447  LinkedPrefDirVectorNumber = PD3;
13448  Utilities->CallLogPop(2288);
13449  return(true);
13450  }
13451  }
13452  LinkedPrefDirVectorNumber = -1;
13453  Utilities->CallLogPop(2289);
13454  return(false);
13455  }
13456  else //buffer or continuation, no link at position 0 but not a failure
13457  {
13458  LinkedPrefDirVectorNumber = -1;
13459  Utilities->CallLogPop(2290);
13460  return(true);
13461  }
13462  }
13463  catch(const Exception &e) //non error catch
13464  {
13465  LinkedPrefDirVectorNumber = -1;
13466  Utilities->CallLogPop(2291);
13467  return(false);
13468  }
13469 }
13470 
13471 // ---------------------------------------------------------------------------
13472 
13473 bool TOnePrefDir::FindLinkingCompatiblePrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
13474 { //not used after modified the pref dir checking function at v2.13.0
13475  // Finds a pref dir element that links to another element at given vector number and link number & position, returns true if finds same direction pref dir with linked
13476  // vector number, true if buffer or continuation with link at blank end & linked vector number = -1, or false if not found with vector number == -1
13477  try
13478  {
13479  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindLinkingCompatiblePrefDir," + AnsiString(PrefDirVectorNumber)
13480  + "," + AnsiString(LinkNumberPos));
13481  bool FoundFlag;
13482  int PD0, PD1, PD2, PD3;
13483  if(PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos] > -1)
13484  {
13485  GetVectorPositionsFromPrefDir4MultiMap(31, Track->TrackElementAt(1463, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).HLoc,
13486  Track->TrackElementAt(1464, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).VLoc, FoundFlag,
13487  PD0, PD1, PD2, PD3);
13488  if(!FoundFlag)
13489  {
13490  Utilities->CallLogPop(2468);
13491  return(false);
13492  }
13493  if((PrefDirVector.at(PrefDirVectorNumber).TrackType == GapJump) && (LinkNumberPos == 0)) //0 is the gap position
13494  { //only PD0 or 1 will be set, else have track linking error that will be found earlier
13495  if(PD0 > -1)
13496  {
13497  if((PrefDirVector.at(PD0).TrackType == GapJump) && ((PrefDirVector.at(PrefDirVectorNumber).ELink == (10 - PrefDirVector.at(PD0).XLink))
13498  || (PrefDirVector.at(PrefDirVectorNumber).XLink == (10 - PrefDirVector.at(PD0).ELink))))
13499  {
13500  LinkedPrefDirVectorNumber = PD0;
13501  Utilities->CallLogPop(2469);
13502  return(true);
13503  }
13504  }
13505  if(PD1 > -1)
13506  {
13507  if((PrefDirVector.at(PD1).TrackType == GapJump) && ((PrefDirVector.at(PrefDirVectorNumber).ELink == (10 - PrefDirVector.at(PD1).XLink))
13508  || (PrefDirVector.at(PrefDirVectorNumber).XLink == (10 - PrefDirVector.at(PD1).ELink))))
13509  {
13510  LinkedPrefDirVectorNumber = PD1;
13511  Utilities->CallLogPop(2470);
13512  return(true);
13513  }
13514  }
13515  LinkedPrefDirVectorNumber = -1;
13516  Utilities->CallLogPop(2471);
13517  return(false);
13518  }
13519  if(PD0 > -1)
13520  {
13521  if((PrefDirVector.at(PD0).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD0).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
13522  {
13523  LinkedPrefDirVectorNumber = PD0;
13524  Utilities->CallLogPop(2472);
13525  return(true);
13526  }
13527  }
13528  if(PD1 > -1)
13529  {
13530  if((PrefDirVector.at(PD1).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD1).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
13531  {
13532  LinkedPrefDirVectorNumber = PD1;
13533  Utilities->CallLogPop(2473);
13534  return(true);
13535  }
13536  }
13537  if(PD2 > -1)
13538  {
13539  if((PrefDirVector.at(PD2).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD2).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
13540  {
13541  LinkedPrefDirVectorNumber = PD2;
13542  Utilities->CallLogPop(2474);
13543  return(true);
13544  }
13545  }
13546  if(PD3 > -1)
13547  {
13548  if((PrefDirVector.at(PD3).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD3).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
13549  {
13550  LinkedPrefDirVectorNumber = PD3;
13551  Utilities->CallLogPop(2475);
13552  return(true);
13553  }
13554  }
13555  LinkedPrefDirVectorNumber = -1;
13556  Utilities->CallLogPop(2476);
13557  return(false);
13558  }
13559  else //buffer or continuation, no link at position 0 but not a failure
13560  {
13561  LinkedPrefDirVectorNumber = -1;
13562  Utilities->CallLogPop(2477);
13563  return(true);
13564  }
13565  }
13566  catch(const Exception &e) //non error catch
13567  {
13568  LinkedPrefDirVectorNumber = -1;
13569  Utilities->CallLogPop(2478);
13570  return(false);
13571  }
13572 }
13573 
13574 // ---------------------------------------------------------------------------
13575 
13577 {
13578  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BiDirectionalPrefDir");
13579  bool FoundFlag; //not used
13580  int PD0, PD1, PD2, PD3;
13581  //recover all PDs at the H & V of PDPtr
13582  GetVectorPositionsFromPrefDir4MultiMap(15, PDPtr->first.first, PDPtr->first.second, FoundFlag, PD0, PD1, PD2, PD3);
13583 
13584  int ELink = PrefDirVector.at(PDPtr->second).GetELink();
13585  int XLink = PrefDirVector.at(PDPtr->second).GetXLink();
13586 
13587  if(PD0 > -1) //ok if PDPtr->second == PD0 as won't find a match, same for others
13588  {
13589  if((PrefDirVector.at(PD0).GetELink() == XLink) && (PrefDirVector.at(PD0).GetXLink() == ELink))
13590  {
13591  Utilities->CallLogPop(2292);
13592  return(true);
13593  }
13594  }
13595  if(PD1 > -1)
13596  {
13597  if((PrefDirVector.at(PD1).GetELink() == XLink) && (PrefDirVector.at(PD1).GetXLink() == ELink))
13598  {
13599  Utilities->CallLogPop(2293);
13600  return(true);
13601  }
13602  }
13603  if(PD2 > -1)
13604  {
13605  if((PrefDirVector.at(PD2).GetELink() == XLink) && (PrefDirVector.at(PD2).GetXLink() == ELink))
13606  {
13607  Utilities->CallLogPop(2294);
13608  return(true);
13609  }
13610  }
13611  if(PD3 > -1)
13612  {
13613  if((PrefDirVector.at(PD3).GetELink() == XLink) && (PrefDirVector.at(PD3).GetXLink() == ELink))
13614  {
13615  Utilities->CallLogPop(2295);
13616  return(true);
13617  }
13618  }
13619  Utilities->CallLogPop(2296);
13620  return(false);
13621 }
13622 
13623 // ---------------------------------------------------------------------------
13624 
13625 void TOnePrefDir::StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
13626 /*
13627  LoadPrefDirElement is stored in both the PrefDirVector and in PrefDir4MultiMap.
13628 */
13629 {
13630  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StorePrefDirElement," + LoadPrefDirElement.LogPrefDir());
13631  PrefDirVector.push_back(LoadPrefDirElement);
13632  THVPair PrefDir4MultiMapKeyPair;
13633  TPrefDir4MultiMapEntry PrefDir4MultiMapEntry;
13634 
13635  PrefDir4MultiMapKeyPair.first = LoadPrefDirElement.HLoc;
13636  PrefDir4MultiMapKeyPair.second = LoadPrefDirElement.VLoc;
13637  PrefDir4MultiMapEntry.first = PrefDir4MultiMapKeyPair;
13638  PrefDir4MultiMapEntry.second = LastElementNumber(68);
13639  PrefDir4MultiMap.insert(PrefDir4MultiMapEntry);
13640 // CheckPrefDir4MultiMap(1);Drop here as takes too long - call it by each calling function
13641  Utilities->CallLogPop(186);
13642 }
13643 
13644 // ---------------------------------------------------------------------------
13645 
13646 void TOnePrefDir::ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
13647 /*
13648  Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNumbers in
13649  4MultiMap if they are greater than the erased value.
13650 */
13651 {
13652  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErasePrefDirElementAt," + AnsiString(PrefDirVectorPosition));
13653  bool FoundFlag;
13654 
13655  if(!PrefDirVector.empty())
13656  {
13657  TPrefDir4MultiMapIterator EraseIt = GetExactMatchFrom4MultiMap(0, PrefDirVectorPosition, FoundFlag);
13658  if(!FoundFlag)
13659  {
13660  throw Exception("Failed to find PrefDir4MultiMap erase element");
13661  }
13662  PrefDirVector.erase(PrefDirVector.begin() + PrefDirVectorPosition);
13663  PrefDir4MultiMap.erase(EraseIt);
13664  DecrementPrefDirElementNumbersInPrefDir4MultiMap(0, PrefDirVectorPosition);
13666  }
13667  Utilities->CallLogPop(187);
13668 }
13669 
13670 // ---------------------------------------------------------------------------
13671 
13672 void TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
13673 /*
13674  Called after ErasePrefDirElementAt(int PrefDirVectorPosition) to decrement the remaining PrefDirElementNumbers in
13675  4MultiMap if they are greater than the erased value.
13676 */
13677 {
13678  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementPrefDirElementNumbersInPrefDir4MultiMap," +
13679  AnsiString(ErasedElementNumber));
13680  if(!PrefDir4MultiMap.empty())
13681  {
13682  for(TPrefDir4MultiMapIterator MapPtr = PrefDir4MultiMap.begin(); MapPtr != PrefDir4MultiMap.end(); MapPtr++)
13683  {
13684  if(MapPtr->second > ErasedElementNumber)
13685  {
13686  MapPtr->second--;
13687  }
13688  }
13689  }
13690  Utilities->CallLogPop(1450);
13691 }
13692 
13693 // ---------------------------------------------------------------------------
13694 
13695 TOnePrefDir::TPrefDir4MultiMapIterator TOnePrefDir::GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
13696 /*
13697  Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition. Used during
13698  ErasePrefDirElementAt(int PrefDirVectorPosition) to erase the relevant element in the multimap. If
13699  nothing is found this is an error but the error message is given in the calling function.
13700 */
13701 {
13702  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetExactMatchFrom4MultiMap," + AnsiString(PrefDirVectorPosition));
13703  FoundFlag = false;
13704  if(PrefDirVectorPosition >= PrefDirVector.size())
13705  {
13706  throw Exception("PrefDirVectorPosition out of range");
13707  }
13708  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(14, PrefDirVectorPosition);
13709  THVPair PrefDir4MultiMapKeyPair;
13710 
13711  PrefDir4MultiMapKeyPair.first = PrefDirElement.HLoc;
13712  PrefDir4MultiMapKeyPair.second = PrefDirElement.VLoc;
13713  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13714 
13715  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
13716  if(ItPair.first == ItPair.second)
13717  {
13718  Utilities->CallLogPop(188);
13719  return(ItPair.first); // nothing found but have to return an iterator, FoundFlag indicates nothing found
13720  }
13721  else
13722  {
13723  if(ItPair.first->second == PrefDirVectorPosition)
13724  {
13725  FoundFlag = true;
13726  Utilities->CallLogPop(189);
13727  return(ItPair.first);
13728  }
13729  ItPair.first++;
13730  if(ItPair.first == ItPair.second)
13731  {
13732  Utilities->CallLogPop(190);
13733  return(ItPair.first); // nothing found
13734  }
13735  if(ItPair.first->second == PrefDirVectorPosition)
13736  {
13737  FoundFlag = true;
13738  Utilities->CallLogPop(191);
13739  return(ItPair.first);
13740  }
13741  ItPair.first++;
13742  if(ItPair.first == ItPair.second)
13743  {
13744  Utilities->CallLogPop(192);
13745  return(ItPair.first); // nothing found
13746  }
13747  if(ItPair.first->second == PrefDirVectorPosition)
13748  {
13749  FoundFlag = true;
13750  Utilities->CallLogPop(193);
13751  return(ItPair.first);
13752  }
13753  ItPair.first++;
13754  if(ItPair.first == ItPair.second)
13755  {
13756  Utilities->CallLogPop(194);
13757  return(ItPair.first); // nothing found
13758  }
13759  if(ItPair.first->second == PrefDirVectorPosition)
13760  {
13761  FoundFlag = true;
13762  Utilities->CallLogPop(195);
13763  return(ItPair.first);
13764  }
13765  }
13766  Utilities->CallLogPop(196);
13767  return(ItPair.first); // nothing found
13768 }
13769 
13770 // ---------------------------------------------------------------------------
13771 
13772 int TOnePrefDir::GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
13773 /*
13774  Although there may be up to four entries at one H & V position this function gets just one. It is
13775  used in EraseFromPrefDirVectorAnd4MultiMap by being called as many times as there are PrefDir elements
13776  at H & V.
13777 */
13778 {
13779  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetOnePrefDirPosition," + AnsiString(HLoc) + "," + AnsiString(VLoc));
13780  THVPair PrefDir4MultiMapKeyPair;
13781 
13782  PrefDir4MultiMapKeyPair.first = HLoc;
13783  PrefDir4MultiMapKeyPair.second = VLoc;
13784  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13785 
13786  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
13787  if(ItPair.first == ItPair.second) // nothing found
13788  {
13789  Utilities->CallLogPop(197);
13790  return(-1);
13791  }
13792  else
13793  {
13794  Utilities->CallLogPop(198);
13795  return(ItPair.first->second);
13796  }
13797 }
13798 
13799 // ---------------------------------------------------------------------------
13800 
13801 void TOnePrefDir::RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
13802 {
13803  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RealignAfterTrackErase," + AnsiString(ErasedTrackVectorPosition));
13804  bool ErasedFlag = false;
13805 
13806  if(ErasedTrackVectorPosition > -1) // should be in calling function but include here as a safeguard
13807  {
13808  if(PrefDirSize() == 0)
13809  {
13810  Utilities->CallLogPop(1511);
13811  return;
13812  }
13813  for(int x = (PrefDirSize() - 1); x >= 0; x--) // reverse because of erase
13814  {
13815  ErasedFlag = false;
13816  // use 'else' to ensure don't try to access an erased element
13817  if(PrefDirVector.at(x).TrackVectorPosition == ErasedTrackVectorPosition)
13818  {
13819  ErasePrefDirElementAt(11, x);
13820  ErasedFlag = true;
13821  }
13822  else if(PrefDirVector.at(x).Conn[0] == ErasedTrackVectorPosition)
13823  {
13824  ErasePrefDirElementAt(12, x);
13825  ErasedFlag = true;
13826  }
13827  else if(PrefDirVector.at(x).Conn[1] == ErasedTrackVectorPosition)
13828  {
13829  ErasePrefDirElementAt(13, x);
13830  ErasedFlag = true;
13831  }
13832  else if(PrefDirVector.at(x).Conn[2] == ErasedTrackVectorPosition)
13833  {
13834  ErasePrefDirElementAt(9, x);
13835  ErasedFlag = true;
13836  }
13837  else if(PrefDirVector.at(x).Conn[3] == ErasedTrackVectorPosition)
13838  {
13839  ErasePrefDirElementAt(10, x);
13840  ErasedFlag = true;
13841  }
13842  if(!ErasedFlag)
13843  {
13844  // don't use 'else' here as may be more than one that need decrementing
13845  if(PrefDirVector.at(x).TrackVectorPosition > ErasedTrackVectorPosition)
13846  {
13847  PrefDirVector.at(x).TrackVectorPosition--;
13848  }
13849  if(PrefDirVector.at(x).Conn[0] > ErasedTrackVectorPosition)
13850  {
13851  PrefDirVector.at(x).Conn[0]--;
13852  }
13853  if(PrefDirVector.at(x).Conn[1] > ErasedTrackVectorPosition)
13854  {
13855  PrefDirVector.at(x).Conn[1]--;
13856  }
13857  if(PrefDirVector.at(x).Conn[2] > ErasedTrackVectorPosition)
13858  {
13859  PrefDirVector.at(x).Conn[2]--;
13860  }
13861  if(PrefDirVector.at(x).Conn[3] > ErasedTrackVectorPosition)
13862  {
13863  PrefDirVector.at(x).Conn[3]--;
13864  }
13865  }
13866  }
13867  }
13868  Utilities->CallLogPop(1434);
13869 }
13870 
13871 // ---------------------------------------------------------------------------
13872 
13873 void TOnePrefDir::CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
13874 {
13875  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcDistanceAndSpeed");
13876  OverallDistance = 0;
13877  OverallSpeedLimit = 0;
13878  LeadingPointsAtLastElement = false;
13879  if(PrefDirSize() == 0) // shouldn't be empty when this called
13880  {
13881  Utilities->CallLogPop(1491);
13882  return;
13883  }
13884  if((LastElementPtr(21)->TrackType == Points) && (LastElementPtr(22)->ELinkPos != 1) && (LastElementPtr(23)->ELinkPos != 3))
13885  {
13886  LeadingPointsAtLastElement = true;
13887  Utilities->CallLogPop(1492);
13888  return;
13889  }
13890  for(unsigned int x = 0; x < PrefDirSize(); x++)
13891  {
13892  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(166, x);
13893  if((PrefDirElement.GetELinkPos() > 1) || (PrefDirElement.GetXLinkPos() > 1)) // 'or' because points may have one == 0 & other == 3
13894  {
13895  OverallDistance += PrefDirElement.Length23;
13896  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
13897  {
13898  if(x == 0)
13899  {
13900  OverallSpeedLimit = PrefDirElement.SpeedLimit23;
13901  }
13902  else
13903  {
13904  if(OverallSpeedLimit != PrefDirElement.SpeedLimit23)
13905  {
13906  OverallSpeedLimit = -1;
13907  }
13908  }
13909  }
13910  }
13911  else
13912  {
13913  OverallDistance += PrefDirElement.Length01;
13914  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
13915  {
13916  if(x == 0)
13917  {
13918  OverallSpeedLimit = PrefDirElement.SpeedLimit01;
13919  }
13920  else
13921  {
13922  if(OverallSpeedLimit != PrefDirElement.SpeedLimit01)
13923  {
13924  OverallSpeedLimit = -1;
13925  }
13926  }
13927  }
13928  }
13929  }
13930  Utilities->CallLogPop(1529);
13931 }
13932 
13933 // ---------------------------------------------------------------------------
13934 
13935 void TOnePrefDir::WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
13936 {
13937  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WritePrefDirToImage");
13938  if(PrefDirSize() == 0)
13939  {
13940  Utilities->CallLogPop(1564);
13941  return;
13942  }
13943  int H, V, HLoc, VLoc, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13944  bool FoundFlag;
13946  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
13947 
13948  while(MMIT != PrefDir4MultiMap.end())
13949  {
13950  HLoc = MMIT->first.first;
13951  VLoc = MMIT->first.second;
13952  GetVectorPositionsFromPrefDir4MultiMap(7, HLoc, VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13953  H = HLoc - Track->GetHLocMin();
13954  V = VLoc - Track->GetVLocMin();
13955  // always found in order, any missing have PrefDirPosx == -1
13956  if(PrefDirPos0 > -1)
13957  {
13958  PrefDirElement0 = GetFixedPrefDirElementAt(174, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
13959  }
13960  if(PrefDirPos1 > -1)
13961  {
13962  PrefDirElement1 = GetFixedPrefDirElementAt(175, PrefDirPos1);
13963  }
13964  if(PrefDirPos2 > -1)
13965  {
13966  PrefDirElement2 = GetFixedPrefDirElementAt(176, PrefDirPos2);
13967  }
13968  if(PrefDirPos3 > -1)
13969  {
13970  PrefDirElement3 = GetFixedPrefDirElementAt(177, PrefDirPos3);
13971  }
13972  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
13973  {
13974  // need to plot all 4 in order to obtain all the direction graphics
13975  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13976  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13977  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13978  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13979  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13980  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13981  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
13982  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
13983  MMIT++;
13984  MMIT++;
13985  MMIT++;
13986  MMIT++;
13987  }
13988  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
13989  {
13990  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
13991  {
13992  // 0 & 1 constitute the bidirectional PrefDir
13993  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13994  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13995  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13996  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13997  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
13998  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
13999  MMIT++;
14000  MMIT++;
14001  MMIT++;
14002  }
14003  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
14004  {
14005  // 0 & 2 constitute the bidirectional PrefDir
14006  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14007  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14008  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
14009  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
14010  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
14011  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
14012  MMIT++;
14013  MMIT++;
14014  MMIT++;
14015  }
14016  else
14017  {
14018  // 1 & 2 constitute the bidirectional PrefDir
14019  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14020  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14021  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
14022  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
14023  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
14024  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
14025  MMIT++;
14026  MMIT++;
14027  MMIT++;
14028  }
14029  }
14030  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
14031  {
14032  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
14033  {
14034  // 0 & 1 constitute the bidirectional PrefDir
14035  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14036  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14037  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14038  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14039  MMIT++;
14040  MMIT++;
14041  }
14042  else
14043  {
14044  // 2 unidirectional PrefDirs
14045  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
14046  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
14047  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
14048  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
14049  MMIT++;
14050  MMIT++;
14051  }
14052  }
14053  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
14054  {
14055  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
14056  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
14057  MMIT++;
14058  }
14059  }
14060  Utilities->CallLogPop(1565);
14061 }
14062 
14063 // ---------------------------------------------------------------------------
14064 
14065 bool TOnePrefDir::PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos) // added at v1.2.0
14066 /*
14067  Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entry position, not points, crossovers,
14068  level crossing, signals with wrong direction set, or buffers.
14069 */
14070 {
14071  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteElementValid");
14072  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
14073  bool FoundFlag;
14075  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
14076 
14077  if((ElementIn.TrackType == Points) || (ElementIn.TrackType == Crossover) || (ElementIn.TrackType == Buffers) || (Track->IsLCAtHV(49, ElementIn.HLoc,
14078  ElementIn.VLoc)))
14079  {
14080  Utilities->CallLogPop(1982);
14081  return(false);
14082  }
14083  if((ElementIn.TrackType == SignalPost) && (ElementIn.Config[EntryPos] == Signal)) // Signal is at exit end
14084  {
14085  Utilities->CallLogPop(1983);
14086  return(false);
14087  }
14088  if((ElementIn.TrackType == SignalPost) && (ElementIn.SigAspect == TTrackElement::GroundSignal))
14089  {
14090  Utilities->CallLogPop(1995);
14091  return(false);
14092  }
14093 // Now check that there is only a single prefdir set
14094  GetVectorPositionsFromPrefDir4MultiMap(8, ElementIn.HLoc, ElementIn.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14095 // always found in order, any missing have PrefDirPosx == -1
14096  if(PrefDirPos0 > -1)
14097  {
14098  PrefDirElement0 = GetFixedPrefDirElementAt(213, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
14099  }
14100  if(PrefDirPos1 > -1)
14101  {
14102  PrefDirElement1 = GetFixedPrefDirElementAt(214, PrefDirPos1);
14103  }
14104  if(PrefDirPos2 > -1)
14105  {
14106  PrefDirElement2 = GetFixedPrefDirElementAt(215, PrefDirPos2);
14107  }
14108  if(PrefDirPos3 > -1)
14109  {
14110  PrefDirElement3 = GetFixedPrefDirElementAt(216, PrefDirPos3);
14111  }
14112  if(PrefDirPos3 > -1) // 4 found, all bidirectional
14113  {
14114  Utilities->CallLogPop(1984);
14115  return(false);
14116  }
14117  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
14118  {
14119  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos) || (PrefDirElement2.XLinkPos == EntryPos))
14120  {
14121  Utilities->CallLogPop(1985);
14122  return(false);
14123  }
14124  else
14125  {
14126  Utilities->CallLogPop(1986);
14127  return(true);
14128  }
14129  }
14130  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
14131  {
14132  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos))
14133  {
14134  Utilities->CallLogPop(1987);
14135  return(false);
14136  }
14137  else
14138  {
14139  Utilities->CallLogPop(1988);
14140  return(true);
14141  }
14142  }
14143  else if(PrefDirPos0 > -1) // one found, make sure in correct direction
14144  {
14145  if(PrefDirElement0.XLinkPos == EntryPos)
14146  {
14147  Utilities->CallLogPop(1989);
14148  return(false);
14149  }
14150  else
14151  {
14152  Utilities->CallLogPop(1990);
14153  return(true);
14154  }
14155  }
14156  else
14157  {
14158  Utilities->CallLogPop(1991);
14159  return(false); // none found
14160  }
14161 }
14162 
14163 // ---------------------------------------------------------------------------
14164 
14166 {
14167 /* //Added at v2.1.0
14168  Called by GetStartAndEndPrefDirElements, which in turn is called by PresetAutoSigRoutesButtonClick. Checks for a diagonal link in
14169  the autosigsroute being fouled by an adjacent track with a corresponding link that meets at the diagonal link, and if it is it
14170  returns true and prevents the route being set. Note that adjacent track consisting of buffers, gaps and continuations at the
14171  diagonal link are also excluded though they need not be, but it makes the check code simpler and such adjacent track is untidy
14172  and can be modelled better anyway.
14173 
14174  Enter with PrefDirElement whose XLink is to be checked for track that fouls a diagonal.
14175  If XLink is anything but 1,3,7 or 9 return false - no fouling as not a diagonal.
14176  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
14177  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
14178  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
14179  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
14180 */
14181  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteDiagonalFouledByTrack," + ElementIn.HLoc + "," +
14182  ElementIn.VLoc + "," + XLink);
14183  int TrackVecPos;
14184  bool TrackFoundFlag;
14185  TTrackElement TempTrackElement;
14186 
14187  if((XLink == 2) || (XLink == 4) || (XLink == 6) || (XLink == 8))
14188  {
14189  Utilities->CallLogPop(2047);
14190  return(false);
14191  }
14192 // for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
14193  if(XLink == 1)
14194  {
14195  TrackVecPos = Track->GetVectorPositionFromTrackMap(48, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
14196  if(TrackFoundFlag)
14197  {
14198  TempTrackElement = Track->TrackElementAt(898, TrackVecPos);
14199  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
14200  {
14201  Utilities->CallLogPop(2048);
14202  return(true);
14203  }
14204  }
14205  TrackVecPos = Track->GetVectorPositionFromTrackMap(49, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
14206  if(TrackFoundFlag)
14207  {
14208  TempTrackElement = Track->TrackElementAt(899, TrackVecPos);
14209  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
14210  {
14211  Utilities->CallLogPop(2049);
14212  return(true);
14213  }
14214  }
14215  }
14216 // for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
14217  if(XLink == 3)
14218  {
14219  TrackVecPos = Track->GetVectorPositionFromTrackMap(50, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
14220  if(TrackFoundFlag)
14221  {
14222  TempTrackElement = Track->TrackElementAt(900, TrackVecPos);
14223  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
14224  {
14225  Utilities->CallLogPop(2050);
14226  return(true);
14227  }
14228  }
14229  TrackVecPos = Track->GetVectorPositionFromTrackMap(51, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
14230  if(TrackFoundFlag)
14231  {
14232  TempTrackElement = Track->TrackElementAt(901, TrackVecPos);
14233  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
14234  {
14235  Utilities->CallLogPop(2051);
14236  return(true);
14237  }
14238  }
14239  }
14240 // for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
14241  if(XLink == 7)
14242  {
14243  TrackVecPos = Track->GetVectorPositionFromTrackMap(52, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
14244  if(TrackFoundFlag)
14245  {
14246  TempTrackElement = Track->TrackElementAt(902, TrackVecPos);
14247  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
14248  {
14249  Utilities->CallLogPop(2052);
14250  return(true);
14251  }
14252  }
14253  TrackVecPos = Track->GetVectorPositionFromTrackMap(53, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
14254  if(TrackFoundFlag)
14255  {
14256  TempTrackElement = Track->TrackElementAt(903, TrackVecPos);
14257  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
14258  {
14259  Utilities->CallLogPop(2053);
14260  return(true);
14261  }
14262  }
14263  }
14264 // for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
14265  if(XLink == 9)
14266  {
14267  TrackVecPos = Track->GetVectorPositionFromTrackMap(54, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
14268  if(TrackFoundFlag)
14269  {
14270  TempTrackElement = Track->TrackElementAt(904, TrackVecPos);
14271  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
14272  {
14273  Utilities->CallLogPop(2054);
14274  return(true);
14275  }
14276  }
14277  TrackVecPos = Track->GetVectorPositionFromTrackMap(55, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
14278  if(TrackFoundFlag)
14279  {
14280  TempTrackElement = Track->TrackElementAt(905, TrackVecPos);
14281  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
14282  {
14283  Utilities->CallLogPop(2055);
14284  return(true);
14285  }
14286  }
14287  }
14288  Utilities->CallLogPop(2056);
14289  return(false);
14290 }
14291 
14292 // ---------------------------------------------------------------------------
14293 
14294 bool TOnePrefDir::GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
14295 {
14296 /* Called by PresetAutoSigRoutesButtonClick in the Interface unit. LastIteratorValue gives the position in EveryPrefDir to start from. Search
14297  EveryPrefDir for continuations (facing inwards wrt pref dir) or non-ground signals in single direction pref dirs, and when find one track forwards
14298  to the next non-ground signal or continuation. If, before finding a valid signal or continuation find points, crossover, level crossing or buffers,
14299  or an element that is already in a route, stop tracking and continue with the search for another valid continuation or signal. When find a suitable
14300  pair, return the elements in StartElement and EndElement, and also the LastIteratorValue ready for the next call.
14301 */
14302  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetStartAndEndPrefDirElements," + AnsiString(LastIteratorValue));
14304  bool FoundFlag, ContFlag, FoundElements = false;
14305  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
14306  TPrefDirElement NextElement;
14307 
14308  for(PDVIt = (PrefDirVector.begin() + LastIteratorValue); PDVIt < PrefDirVector.end(); PDVIt++)
14309  {
14310  LastIteratorValue++;
14311  ContFlag = false;
14312  if((PDVIt->TrackType != SignalPost) && (PDVIt->TrackType != Continuation))
14313  {
14314  continue;
14315  }
14316  if((PDVIt->TrackType == SignalPost) && (PDVIt->SigAspect == TTrackElement::GroundSignal))
14317  {
14318  continue;
14319  }
14320 // if(AllRoutes::TrackIsInARoute(, PDVIt->TrackVectorPosition, PDVIt->EntryPos) continue; //already in a route - no, don't check start position as if a signal might well be at end of an existing route
14321  // found a potential route start point
14322  if(PresetAutoRouteDiagonalFouledByTrack(0, *PDVIt, PDVIt->XLink)) // Added at v2.1.0
14323  {
14324  continue;
14325  }
14326  if(PresetAutoRouteElementValid(0, *PDVIt, PDVIt->ELinkPos))
14327  {
14328  // check if continuation either in a route or with prefdir facing 'End' (OK if find it as EndElement, but not as StartElement)
14329  if(PDVIt->TrackType == Continuation)
14330  {
14331  if(AllRoutes->TrackIsInARoute(18, PDVIt->TrackVectorPosition, PDVIt->ELinkPos))
14332  {
14333  continue;
14334  }
14335  if(PDVIt->XLinkPos == 0) // position 0 is the continuation
14336  {
14337  continue;
14338  }
14339  }
14340  StartElement = *PDVIt;
14341 // in Glenn Mitchell's error log (14/04/13) the offending signal start position was 4680, problem was it linked to a point with pref dirs set on through track but signal linked to
14342  // diverging track on which there was no pref dir. See below for 2 required changes.
14343  }
14344  else
14345  {
14346  continue;
14347  }
14348  // now track along until find a signal or continuation, checking validity for each element
14349  int NextTrackVectorPosition = PDVIt->Conn[PDVIt->GetXLinkPos()];
14350  GetVectorPositionsFromPrefDir4MultiMap(9, Track->TrackElementAt(878, NextTrackVectorPosition).HLoc,
14351  Track->TrackElementAt(879, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14352  if(PrefDirPos0 == -1) // no continuing prefdir
14353  {
14354  continue;
14355  }
14356  bool NextElementFoundFlag = false;
14357  if(GetFixedPrefDirElementAt(217, PrefDirPos0).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14358  {
14359  NextElement = GetFixedPrefDirElementAt(218, PrefDirPos0);
14360  NextElementFoundFlag = true;
14361  }
14362  if(PrefDirPos1 > -1)
14363  {
14364  if(GetFixedPrefDirElementAt(219, PrefDirPos1).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14365  {
14366  NextElement = GetFixedPrefDirElementAt(220, PrefDirPos1);
14367  NextElementFoundFlag = true;
14368  }
14369  }
14370  if(PrefDirPos2 > -1)
14371  {
14372  if(GetFixedPrefDirElementAt(221, PrefDirPos2).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14373  {
14374  NextElement = GetFixedPrefDirElementAt(222, PrefDirPos2);
14375  NextElementFoundFlag = true;
14376  }
14377  }
14378  if(PrefDirPos3 > -1)
14379  {
14380  if(GetFixedPrefDirElementAt(223, PrefDirPos3).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14381  {
14382  NextElement = GetFixedPrefDirElementAt(224, PrefDirPos3);
14383  NextElementFoundFlag = true;
14384  }
14385  }
14386  if(!NextElementFoundFlag)
14387  {
14388  continue; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
14389 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (1)")); //[GM error 14/04/13] for next release change this to 'continue;' to quit from trying to find the auto route (don't need to throw an exception)
14390  }
14391  while(true)
14392  {
14393  // check validity
14394  if(PresetAutoRouteDiagonalFouledByTrack(1, NextElement, NextElement.XLink)) // Added at v2.1.0
14395  {
14396  ContFlag = true;
14397  break;
14398  }
14399  if(!PresetAutoRouteElementValid(1, NextElement, NextElement.ELinkPos))
14400  {
14401  ContFlag = true;
14402  break;
14403  }
14404  // check if in a route, providing not a signal, as a signal might be at the start of a route
14405  if(NextElement.TrackType != SignalPost)
14406  {
14407  if(AllRoutes->TrackIsInARoute(17, NextElement.TrackVectorPosition, NextElement.ELinkPos))
14408  {
14409  ContFlag = true;
14410  break;
14411  }
14412  }
14413  if((NextElement.TrackType == SignalPost) || (NextElement.TrackType == Continuation))
14414  // can't be a gound signal as would have failed the validity test
14415  {
14416  EndElement = NextElement;
14417  break;
14418  }
14419  // get the next element in the sequence
14420  NextTrackVectorPosition = NextElement.Conn[NextElement.GetXLinkPos()];
14421  GetVectorPositionsFromPrefDir4MultiMap(10, Track->TrackElementAt(880, NextTrackVectorPosition).HLoc,
14422  Track->TrackElementAt(881, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14423  if(PrefDirPos0 == -1) // no continuing prefdir
14424  {
14425  ContFlag = true;
14426  break;
14427  }
14428  if(GetFixedPrefDirElementAt(225, PrefDirPos0).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14429  {
14430  NextElement = GetFixedPrefDirElementAt(226, PrefDirPos0);
14431  continue;
14432  }
14433  if(PrefDirPos1 > -1)
14434  {
14435  if(GetFixedPrefDirElementAt(227, PrefDirPos1).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14436  {
14437  NextElement = GetFixedPrefDirElementAt(228, PrefDirPos1);
14438  continue;
14439  }
14440  }
14441  if(PrefDirPos2 > -1)
14442  {
14443  if(GetFixedPrefDirElementAt(229, PrefDirPos2).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14444  {
14445  NextElement = GetFixedPrefDirElementAt(230, PrefDirPos2);
14446  continue;
14447  }
14448  }
14449  if(PrefDirPos3 > -1)
14450  {
14451  if(GetFixedPrefDirElementAt(231, PrefDirPos3).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14452  {
14453  NextElement = GetFixedPrefDirElementAt(232, PrefDirPos3);
14454  continue;
14455  }
14456  }
14457  // had exception thrown here if NextElement not found, but could be a bridge where opposite track PrefDir set, in which case won't find it
14458  // found with Jonathan Kwok's DLR railway (17/11/12) where undertrack PrefDir not set just west of Poplar. Hence first test if element is a bridge
14459  // and if so set ContFlag to true & break (same as not finding PrefDir element at all). Modified at version 1.3.1
14460  // note that it's not NextElement that is to be examined but NextTrackVectorPosition, which can be found easily by using PrefDirPos0 (there will be a
14461  // PrefDirPos0 or would have exited earlier, and it doesn't matter that PrefDirPos0 isn't on the route in question because only the TrackType is needed)
14462  if(GetFixedPrefDirElementAt(243, PrefDirPos0).TrackType == Bridge)
14463  {
14464  ContFlag = true;
14465  break;
14466  }
14467  else
14468  {
14469  ContFlag = true; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
14470  // could drop the bridge test but keep it to show the change history
14471  break;
14472 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (2)")); //[GM error 14/04/13] for next release set ContFlag to true & break' to quit from trying to find the auto route (don't need to throw an exception)
14473  }
14474  }
14475  if(ContFlag)
14476  {
14477  continue;
14478  }
14479  // else have start and end elements set & all elements valid, so set up the route segment
14480  FoundElements = true;
14481  break;
14482  }
14483  if(FoundElements)
14484  {
14485  Utilities->CallLogPop(1992);
14486  return(true);
14487  }
14488  else
14489  {
14490  Utilities->CallLogPop(1993);
14491  return(false);
14492  }
14493 }
14494 
14495 // ---------------------------------------------------------------------------
14496 // TOneRoute
14497 // ---------------------------------------------------------------------------
14498 
14499 bool TOneRoute::GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
14500 {
14501 /* General:
14502  The basis of all these route setting functions, preferred and non-preferred, is that a SearchVector is set up
14503  containing all the new elements to form the route. When complete, the SearchVector is converted into route
14504  elements, either as a new route, or an extension to an existing route. The AutoSigs flag determines whether the
14505  route will use automatic signals or not.
14506  For preferred and non-preferred routes, all new elements (as opposed to those already in existing routes) go
14507  into the SearchVector. For non-preferred routes, trackelements are selected that are not necessarily PrefDir
14508  elements, so additional work is needed to complete all their members before they are ready for conversion into
14509  a route - see SetRemainingSearchVectorValues. The call order is GetStart....; GetNext...,
14510  which includes the Search... function; [SetRemainingSearchVectorValues for non-preferred routes only], then
14511  ConvertAndAdd.......
14512 */
14513  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPreferredRouteStartElement," + AnsiString(HLoc) + "," +
14514  AnsiString(VLoc) + "," + AnsiString((short)AutoSigsFlag));
14515  ClearRoute();
14516  int TrackVectorPosition;
14517  TTrackElement TrackElement;
14518  TPrefDirElement FirstElement, LastElement;
14519 
14520  if(!(Track->FindNonPlatformMatch(7, HLoc, VLoc, TrackVectorPosition, TrackElement)))
14521  {
14522  Utilities->CallLogPop(199);
14523  return(false);
14524  }
14525  if(AutoSigsFlag && (TrackElement.TrackType == Buffers)) // added at v1.2.0
14526  {
14527  TrainController->StopTTClockMessage(80, "Can't create an automatic signal route from buffers");
14528  Utilities->CallLogPop(1996);
14529  return(false);
14530  }
14531  else if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
14532  {
14533  TrainController->StopTTClockMessage(7, "Must select a valid signal, buffers or continuation");
14534  Utilities->CallLogPop(200);
14535  return(false);
14536  }
14537  if(Track->IsLCAtHV(18, HLoc, VLoc))
14538  {
14539  TrainController->StopTTClockMessage(73, "Can't start a route on a level crossing");
14540  Utilities->CallLogPop(1909);
14541  return(false);
14542  }
14543 // check if selected a train & disallow if so
14544  if(TrackElement.TrainIDOnElement > -1)
14545  {
14546  TrainController->StopTTClockMessage(9, "Can't start a route on a train");
14547  Utilities->CallLogPop(202);
14548  return(false);
14549  }
14550 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
14551  TPrefDirElement PrefDirElement;
14552  int LockedVectorNumber;
14553 
14554  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(1, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
14555  {
14556  TrainController->StopTTClockMessage(10, "Can't start a route on a locked route");
14557  Utilities->CallLogPop(203);
14558  return(false);
14559  }
14560  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(2, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
14561  {
14562  TrainController->StopTTClockMessage(11, "Can't start a route on a locked route");
14563  Utilities->CallLogPop(204);
14564  return(false);
14565  }
14567  StartRoutePosition = TrackVectorPosition; // actual route start - may be element following StartRouteSelectPosition if select a
14568 // signal in an autosig route & follow with a non-autosig route
14569 
14570  TPrefDirElement BlankElement;
14571 
14572  StartElement1 = BlankElement;
14573  StartElement2 = BlankElement; //not used in this routine but used in GetNextPreferred.... though could probably dispense with it there
14574 // check it's in a PrefDir (could be 2 entries for two possible PrefDirs, can only select single track elements so can't have more than 2 PrefDirs)
14575  bool InPrefDirFlag = false;
14576 
14577  bool FoundFlag;
14578  int PrefDirPos0 = -1;
14579  int PrefDirPos1 = -1;
14580  int PrefDirPos2 = -1;
14581  int PrefDirPos3 = -1;
14582 
14584  Track->TrackElementAt(85, StartRoutePosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14585  int PrefDirVecPos[4] =
14586  {
14587  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
14588  };
14589 
14590  for(int x = 0; x < 4; x++)
14591  {
14592  int b = PrefDirVecPos[x];
14593  if(b > -1)
14594  {
14595  // only allow the appropriate exit route to be searched
14596  if(((TrackElement.TrackType == SignalPost) && (EveryPrefDir->GetFixedPrefDirElementAt(15, b).Config[EveryPrefDir->GetFixedPrefDirElementAt(16,
14597  b).XLinkPos] == Signal)) || ((TrackElement.TrackType == Buffers) && (EveryPrefDir->GetFixedPrefDirElementAt(17,
14598  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(18, b).XLinkPos] == Connection)) ||
14599  ((TrackElement.TrackType == Continuation) && (EveryPrefDir->GetFixedPrefDirElementAt(19,
14600  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(20, b).XLinkPos] == Connection)))
14601  {
14602  InPrefDirFlag = true;
14603  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(21, b);
14604  if(AutoSigsFlag)
14605  {
14606  StartElement1.AutoSignals = true;
14607  }
14608  StartElement1.PrefDirRoute = true;
14609  }
14610  }
14611  }
14612 
14613  if(!InPrefDirFlag)
14614  {
14615  TrainController->StopTTClockMessage(12, "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
14616  Utilities->CallLogPop(205);
14617  return(false);
14618  }
14619 // look for exact match in a route first - can't be a bridge so can use a simple 'find'
14621  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(14, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
14622 
14623  if(DummyPair.first > -1) // if DummyPair exists then an error as start element can only be in one route (bridges not allowed)
14624  {
14625  throw Exception("Selection in two routes - should never happen!");
14626  }
14627  if(RoutePair.first > -1) // no need to examine DummyPair as start element can only be in one route (bridges not allowed)
14628  {
14629  if(RoutePair.second != AllRoutes->GetFixedRouteAt(1, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
14630  {
14631  TrainController->StopTTClockMessage(13, "Can't start a route within or at the start of an existing route");
14632  Utilities->CallLogPop(206);
14633  return(false);
14634  }
14635  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(2, RoutePair.first).GetFixedPrefDirElementAt(29, RoutePair.second);
14636  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
14637  {
14638  TrainController->StopTTClockMessage(14, "No forward connection from this position");
14639  Utilities->CallLogPop(207);
14640  return(false);
14641  }
14642  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(9, RouteElement.Conn[RouteElement.XLinkPos],
14643  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
14644  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
14645  {
14646  TrainController->StopTTClockMessage(15, "Can't start a route at an element that links forward into an existing route");
14647  Utilities->CallLogPop(208);
14648  return(false);
14649  }
14650  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(158, RoutePair.first).RouteID);
14652  AllRoutes->GetFixedRouteAt(4, RoutePair.first).PrefDirSize() - 1); // last element
14653  if(AutoSigsFlag)
14654  {
14655  StartElement1.AutoSignals = true;
14656  }
14657  StartElement1.PrefDirRoute = true;
14659  Utilities->CallLogPop(209);
14660  return(true); // all retained values (StartElement1 & maybe 2; StartRoutePosition) set
14661  }
14662 
14663  else // no route started
14664  {
14665 // check if selected position is adjacent to start or end of an existing route and disallow
14666  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14667  {
14668  FirstElement = AllRoutes->GetFixedRouteAt(5, a).GetFixedPrefDirElementAt(31, 0);
14669  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
14670  {
14671  TrainController->StopTTClockMessage(16, "Can't make selection adjacent to start of another route");
14672  Utilities->CallLogPop(210);
14673  return(false);
14674  }
14675  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
14676  {
14677  TrainController->StopTTClockMessage(17, "Can't make selection adjacent to start of another route");
14678  Utilities->CallLogPop(211);
14679  return(false);
14680  }
14681  }
14682 
14683 // check if it's adjacent to end of an an existing route,
14684  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14685  {
14687  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
14688  {
14689  TrainController->StopTTClockMessage(18, "Can't start a route adjacent to the end of an existing route");
14690  Utilities->CallLogPop(212);
14691  return(false);
14692  }
14693  }
14694  SearchVector.push_back(StartElement1);
14695  Utilities->CallLogPop(213);
14696  return(true);
14697  }
14698 }
14699 
14700 // ---------------------------------------------------------------------------
14701 
14702 bool TOneRoute::GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag,
14703  IDInt &ReqPosRouteID, bool &PointsChanged)
14704 
14705 /*
14706  Return true if select valid next element, in which case the route is set & stored in SearchVector. Return false for an invalid next element.
14707 
14708  Declare integers EndPosition (the position used) and ReqPosRouteID to hold (when required) the existing route selected (for linking to an existing route),
14709  this being set to -1 for not used.
14710  Check if selection is a valid track element, cancel if not, if select original start element or if select buffers
14711  with AutoSigsFlag set - would have no way out and no way to cancel the route with a train at the buffers.
14712  Check correct type of element - signal/buffers/continuation.
14713  Fail if train on element, or if selection not in EveryPrefDir. Otherwise set EndElement1 & possibly also
14714  EndElement2 corresponding to the 2 possible PrefDir elements).
14715  Check if selection is first element in an existing route & if so set ReqPosRouteID, EndElement1, and set EndElement2 to
14716  blank as can only be one route at that element (can't select bridges). Fail if in a route & not at start, or at start but route
14717  linked forward to another route.
14718  Check & fail if adjacent to start or end of an existing route, or if select the route that selected at start (though earlier check
14719  for same position as start should cover this)
14720 
14721  If there's a StartSelectionRouteID then StartElement1 will be set to the last entry in the selected route so use
14722  SearchForPreferredRoute to search for the selected end element from this start element. If succeed then set the search vector
14723  graphics using SetRouteSearchVectorGraphics(AutoSigsFlag) & return true, for Interface to handle the flashing & time delay. After the
14724  delay completes the Interface flasher calls ConvertAndAddPreferredRouteSearchVector to add the new route to the AllRoutesVectorPtr.
14725  If the search fails then return false.
14726  If there isn't a StartSelectionRouteID then the starting element is not already in a route, so it will have been stored
14727  in the SearchVector to ensure it's entered as part of the new route.
14728  First check whether the selected element (either EndElement1 or 2) is adjacent to the starting position and if so set the route to go
14729  directly to it (as opposed to going round a long loop to get to it just because that XLinkPos happens to be chosen first. If not
14730  adjacent then first search on EndElement1, and if fail search on EndElement2 providing it's set. If succeed
14731  set the search vector graphics as above and return. If reach end of function then have failed to find a valid element,
14732  so return false, with an appropriate message if ConsecSignalsRoute set.
14733 */
14734 
14735 {
14736  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPreferredRouteElement," + AnsiString(HLoc) + "," +
14737  AnsiString(VLoc) + "," + AnsiString((short)ConsecSignals) + "," + AnsiString((short)AutoSigsFlag));
14738  int EndPosition; // the position selected
14739  int NewFailedPointsTVPos = -1; //added at v2.13.0 for point failures
14740 
14741  Track->LCFoundInAutoSigsRoute = false;
14743  TotalSearchCount = 0;
14744  ReqPosRouteID = IDInt(-1); // default value for not used
14745  TTrackElement TrackElement;
14746  TPrefDirElement EndElement1, EndElement2, BlankElement; // all blank to begin with, can only have max of 2 PrefDirs on a
14747  // given element as can't select 2-track elements
14748  if(!(Track->FindNonPlatformMatch(8, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
14749  {
14750  Utilities->CallLogPop(214);
14751  return(false);
14752  }
14753  if(Track->IsLCAtHV(19, HLoc, VLoc))
14754  {
14755  TrainController->StopTTClockMessage(72, "Can't end a route on a level crossing");
14756  Utilities->CallLogPop(1908);
14757  return(false);
14758  }
14759 // cancel selection if on original start element
14760  if(EndPosition == StartRoutePosition)
14761  {
14762  Utilities->CallLogPop(215);
14763  return(false);
14764  }
14765  if(AutoSigsFlag)
14766  {
14767  if(TrackElement.TrackType == Buffers)
14768  {
14769  TrainController->StopTTClockMessage(19, "Can't create an automatic signal route into buffers");
14770  Utilities->CallLogPop(216);
14771  return(false);
14772  }
14773  }
14774  if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
14775  {
14776  TrainController->StopTTClockMessage(20, "Must select a valid signal, buffers or continuation");
14777  Utilities->CallLogPop(217);
14778  return(false);
14779  }
14780 // check if train on element
14781  if(TrackElement.TrainIDOnElement > -1)
14782  {
14783  TrainController->StopTTClockMessage(22, "Can't end a route on a train");
14784  Utilities->CallLogPop(219);
14785  return(false);
14786  }
14787 // disallow if not in EveryPrefDir & set EndElement(s)
14788  bool InPrefDirFlag = false;
14789 
14790  bool FoundFlag;
14791  int PrefDirPos0 = -1;
14792  int PrefDirPos1 = -1;
14793  int PrefDirPos2 = -1;
14794  int PrefDirPos3 = -1;
14795 
14796  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(4, Track->TrackElementAt(86, EndPosition).HLoc, Track->TrackElementAt(87, EndPosition).VLoc, FoundFlag,
14797  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14798  int PrefDirVecPos[4] =
14799  {
14800  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
14801  };
14802 
14803  for(int x = 0; x < 4; x++)
14804  {
14805  int b = PrefDirVecPos[x];
14806  if(b > -1)
14807  {
14808  InPrefDirFlag = true;
14809  if(EndElement1.TrackVectorPosition == -1)
14810  {
14811  EndElement1 = EveryPrefDir->GetFixedPrefDirElementAt(33, b);
14812  }
14813  else
14814  {
14815  EndElement2 = EveryPrefDir->GetFixedPrefDirElementAt(34, b);
14816  }
14817  }
14818  }
14819  if(!InPrefDirFlag)
14820  {
14821  TrainController->StopTTClockMessage(23, "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
14822  Utilities->CallLogPop(220);
14823  return(false);
14824  }
14825 // check if in an existing route - can't be a bridge so can use a simple 'find'
14826 // bool InRoute = false;
14828  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(15, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
14829 
14830  if(RoutePair.first > -1)
14831  {
14832  if(RoutePair.second != 0) // not first element in existing route so no good
14833  {
14834  TrainController->StopTTClockMessage(24, "Can't end a route within or at the end of an existing route");
14835  Utilities->CallLogPop(221);
14836  return(false);
14837  }
14838  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(8, RoutePair.first).GetFixedPrefDirElementAt(35, RoutePair.second);
14839 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
14840  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(10, RouteElement.Conn[RouteElement.ELinkPos],
14841  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
14842  // discovered when timetable building for Joshua Coupe's railway. Also affects non-preferred routes - see below
14843  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
14844  {
14845  TrainController->StopTTClockMessage(25, "Can't start a route within or at the end of an existing route");
14846  Utilities->CallLogPop(222);
14847  return(false);
14848  }
14849  EndElement1 = RouteElement;
14850  EndElement2 = BlankElement; // only need the route element
14851  EndPosition = EndElement1.TrackVectorPosition;
14852  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(160, RoutePair.first).RouteID);
14853  }
14854 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
14855 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
14856 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
14857 
14858  if(EndElement1.HLoc >= StartElement1.HLoc)
14859  {
14861  SearchLimitHighH = EndElement1.HLoc + 15;
14862  }
14863  else
14864  {
14865  SearchLimitLowH = EndElement1.HLoc - 15;
14867  }
14868  if(EndElement1.VLoc >= StartElement1.VLoc)
14869  {
14871  SearchLimitHighV = EndElement1.VLoc + 15;
14872  }
14873  else
14874  {
14875  SearchLimitLowV = EndElement1.VLoc - 15;
14877  }
14878 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
14879  check & TotalSearchCounts check
14880  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
14881  {
14882  TrainController->StopTTClockMessage(65, "Unable to reach the selected element - too far ahead");
14883  Utilities->CallLogPop(1693);
14884  return false;
14885  }
14886 */
14887 // check if adjacent to start and disallow
14888  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14889  {
14891  int AdjLinkPos = AllRoutes->GetFixedRouteAt(218, a).GetFixedPrefDirElementAt(244, 0).ELinkPos; // added at v1.3.1
14892 // if((EndElement1.Config[EndElement1.XLinkPos] != End) &&
14893 // (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition))
14894  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
14895  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
14896  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos))
14897  {
14898  TrainController->StopTTClockMessage(26, "Can't end a route adjacent to the start of an existing route");
14899  Utilities->CallLogPop(223);
14900  return(false);
14901  }
14902 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
14903 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition))
14904  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
14905  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
14906  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos))
14907  {
14908  TrainController->StopTTClockMessage(27, "Can't end a route adjacent to the start of an existing route");
14909  Utilities->CallLogPop(224);
14910  return(false);
14911  }
14912 // check if adjacent to end of a route & disallow
14914  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition))
14915  {
14916  TrainController->StopTTClockMessage(28, "Can't end a route adjacent to the end of an existing route");
14917  Utilities->CallLogPop(225);
14918  return(false);
14919  }
14920  }
14921 
14922 // check for same route as start element
14924  {
14925  TrainController->StopTTClockMessage(29, "Can't select same route as started in");
14926  Utilities->CallLogPop(226);
14927  return(false);
14928  }
14929 // check for a looping route
14930  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
14931  {
14933  {
14934  TrainController->StopTTClockMessage(69, "Can't create a route that loops back on itself");
14935  Utilities->CallLogPop(1844);
14936  return(false);
14937  }
14938  }
14939 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
14940 // so search from this element. No need to add StartElement to the SearchVector since it already exists in a route
14941 // and don't want to add it again
14942  if(StartSelectionRouteID > -1)
14943  {
14944  if(SearchForPreferredRoute(0, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14945  AutoSigsFlag, false))
14946  {
14947  SetRouteSearchVectorGraphics(0, AutoSigsFlag, true); // change graphic colour to the route colour
14948  if(PointsToBeChanged(5, NewFailedPointsTVPos))
14949  {
14950  if(NewFailedPointsTVPos > -1)
14951  {
14952  TTrackElement TE = Track->TrackElementAt(1478, NewFailedPointsTVPos);
14953  TrainController->StopTTClockMessage(97, "Points at " + TE.ElementID +
14954  " failed during route setting.\nTry to find a different route.");
14955  Utilities->CallLogPop(2488);
14956  return(false);
14957  }
14958  PointsChanged = true;
14959  }
14960  Utilities->CallLogPop(227);
14961  return(true);
14962  }
14963  else if(!Track->SuppressRouteFailMessage)
14964  {
14965  //corrected at v2.7.0 - brackets were missed earlier so if SearchForPreferredRoute failed & else condition failed too then returned false with no message
14967  Utilities->CallLogPop(228);
14968  return(false);
14969  }
14970  }
14971  else
14972  {
14973 // Note: StartElement not in an existing route so was added to the searchvector during the earlier function
14974 // First check if selection adjacent to start element and if so use that [can't be as can't have 2 consecutive signals, but leave in]
14975 
14976 // added the XLinkPos checks because of Matt Blades error reported on 28/06/11, where StartElement2 matched EndPosition spuriously
14977 // note that a blank element will have XLinkPos set to -1
14978  if((StartElement1.XLinkPos > -1) && (StartElement1.Conn[StartElement1.XLinkPos] == EndPosition))
14979  {
14980  if(SearchForPreferredRoute(1, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14981  AutoSigsFlag, false))
14982  {
14983  SetRouteSearchVectorGraphics(1, AutoSigsFlag, true); // change graphic colour to the route colour
14984  if(PointsToBeChanged(6, NewFailedPointsTVPos))
14985  {
14986  if(NewFailedPointsTVPos > -1)
14987  {
14988  TTrackElement TE = Track->TrackElementAt(1480, NewFailedPointsTVPos);
14989  TrainController->StopTTClockMessage(99, "Points at " + TE.ElementID +
14990  " failed during route setting.\nTry to find a different route.");
14991  Utilities->CallLogPop(2490);
14992  return(false);
14993  }
14994  PointsChanged = true;
14995  }
14996  Utilities->CallLogPop(229);
14997  return(true);
14998  }
14999  else
15000  {
15002  {
15004  }
15005  Utilities->CallLogPop(230);
15006  return(false);
15007  }
15008  }
15009  else if((StartElement2.XLinkPos > -1) && (StartElement2.Conn[StartElement2.XLinkPos] == EndPosition))
15010  {
15011  if(SearchForPreferredRoute(2, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15012  AutoSigsFlag, false))
15013  {
15014  SetRouteSearchVectorGraphics(2, AutoSigsFlag, true); // change graphic colour to the route colour
15015  if(PointsToBeChanged(7, NewFailedPointsTVPos))
15016  {
15017  if(NewFailedPointsTVPos > -1)
15018  {
15019  TTrackElement TE = Track->TrackElementAt(1482, NewFailedPointsTVPos);
15020  TrainController->StopTTClockMessage(101, "Points at " + TE.ElementID +
15021  " failed during route setting.\nTry to find a different route.");
15022  Utilities->CallLogPop(2492);
15023  return(false);
15024  }
15025  PointsChanged = true;
15026  }
15027  Utilities->CallLogPop(231);
15028  return(true);
15029  }
15030  else
15031  {
15033  {
15035  }
15036  Utilities->CallLogPop(232);
15037  return(false);
15038  }
15039  }
15040  // now start off in the best direction
15041  int BestPos = Track->FindClosestLinkPosition(0, StartRoutePosition, EndPosition); // can only be 0 or 1
15042  // the following logic is very unstructured as extra bits have been added at different times and I'm reluctant to remove earlier bits in case
15043  // they cover situations that might be overlooked. A full analysis would enable it to be tidied up but it works (so far!) so I'll leave it as it is
15044  // unless new problems are found.
15045  if(StartElement1.XLinkPos == BestPos)
15046  {
15047  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15048  if(SearchForPreferredRoute(3, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15049  AutoSigsFlag, false))
15050  {
15051  SetRouteSearchVectorGraphics(3, AutoSigsFlag, true); // change graphic colour to the route colour
15052  if(PointsToBeChanged(8, NewFailedPointsTVPos))
15053  {
15054  if(NewFailedPointsTVPos > -1)
15055  {
15056  TTrackElement TE = Track->TrackElementAt(1484, NewFailedPointsTVPos);
15057  TrainController->StopTTClockMessage(103, "Points at " + TE.ElementID +
15058  " failed during route setting.\nTry to find a different route.");
15059  Utilities->CallLogPop(2494);
15060  return(false);
15061  }
15062  PointsChanged = true;
15063  }
15064  Utilities->CallLogPop(233);
15065  return(true);
15066  }
15067  else if(StartElement2.TrackVectorPosition > -1)
15068  {
15069  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15070  if(SearchForPreferredRoute(4, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15071  AutoSigsFlag, false))
15072  {
15073  SetRouteSearchVectorGraphics(4, AutoSigsFlag, true); // change graphic colour to the route colour
15074  if(PointsToBeChanged(9, NewFailedPointsTVPos))
15075  {
15076  if(NewFailedPointsTVPos > -1)
15077  {
15078  TTrackElement TE = Track->TrackElementAt(1486, NewFailedPointsTVPos);
15079  TrainController->StopTTClockMessage(105, "Points at " + TE.ElementID +
15080  " failed during route setting.\nTry to find a different route.");
15081  Utilities->CallLogPop(2496);
15082  return(false);
15083  }
15084  PointsChanged = true;
15085  }
15086  Utilities->CallLogPop(234);
15087  return(true);
15088  }
15089  }
15090  }
15091  else if(StartElement2.TrackVectorPosition > -1)
15092  {
15093  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15094  if(SearchForPreferredRoute(5, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15095  AutoSigsFlag, false))
15096  {
15097  SetRouteSearchVectorGraphics(6, AutoSigsFlag, true); // change graphic colour to the route colour
15098  if(PointsToBeChanged(10, NewFailedPointsTVPos))
15099  {
15100  if(NewFailedPointsTVPos > -1)
15101  {
15102  TTrackElement TE = Track->TrackElementAt(1488, NewFailedPointsTVPos);
15103  TrainController->StopTTClockMessage(107, "Points at " + TE.ElementID +
15104  " failed during route setting.\nTry to find a different route.");
15105  Utilities->CallLogPop(2498);
15106  return(false);
15107  }
15108  PointsChanged = true;
15109  }
15110  Utilities->CallLogPop(1857);
15111  return(true);
15112  }
15113  else if(SearchForPreferredRoute(8, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15114  AutoSigsFlag, false))
15115  {
15116  SetRouteSearchVectorGraphics(7, AutoSigsFlag, true); // change graphic colour to the route colour
15117  if(PointsToBeChanged(11, NewFailedPointsTVPos))
15118  {
15119  if(NewFailedPointsTVPos > -1)
15120  {
15121  TTrackElement TE = Track->TrackElementAt(1490, NewFailedPointsTVPos);
15122  TrainController->StopTTClockMessage(109, "Points at " + TE.ElementID +
15123  " failed during route setting.\nTry to find a different route.");
15124  Utilities->CallLogPop(2500);
15125  return(false);
15126  }
15127  PointsChanged = true;
15128  }
15129  Utilities->CallLogPop(1858);
15130  return(true);
15131  }
15132  }
15133  else if(StartElement1.XLinkPos == (1 - BestPos))
15134  // added at v0.4d to use StartElement1 again with non-Best direction (may be only one & may not point in right direction)
15135  {
15136  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15137  if(SearchForPreferredRoute(9, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15138  AutoSigsFlag, false))
15139  {
15140  SetRouteSearchVectorGraphics(8, AutoSigsFlag, true); // change graphic colour to the route colour
15141  if(PointsToBeChanged(12, NewFailedPointsTVPos))
15142  {
15143  if(NewFailedPointsTVPos > -1)
15144  {
15145  TTrackElement TE = Track->TrackElementAt(1492, NewFailedPointsTVPos);
15146  TrainController->StopTTClockMessage(111, "Points at " + TE.ElementID +
15147  " failed during route setting.\nTry to find a different route.");
15148  Utilities->CallLogPop(2502);
15149  return(false);
15150  }
15151  PointsChanged = true;
15152  }
15153  Utilities->CallLogPop(1864);
15154  return(true);
15155  }
15156  }
15157  }
15159  {
15161  }
15162  Utilities->CallLogPop(235);
15163  return(false);
15164 }
15165 
15166 // ---------------------------------------------------------------------------
15167 
15168 void TOneRoute::RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
15169 {
15170  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteImageMarker");
15171  if(PrefDirSize() == 0)
15172  {
15173  Utilities->CallLogPop(1704);
15174  return;
15175  }
15176  for(unsigned int x = 0; x < PrefDirSize(); x++)
15177  {
15178  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
15179  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
15180  {
15181  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
15182  TempPrefDirElement.EXGraphicPtr);
15183  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && PrefDirSize() > 1) // Route, no direction if a single element
15184  {
15185  if(x == 0)
15186  {
15187  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
15188  TempPrefDirElement.EntryDirectionGraphicPtr);
15189  }
15190  if(x == (PrefDirSize() - 1))
15191  {
15192  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
15193  TempPrefDirElement.EntryDirectionGraphicPtr);
15194  }
15195  }
15196  }
15197  }
15198 
15199  Utilities->CallLogPop(1705);
15200 }
15201 
15202 // ---------------------------------------------------------------------------
15203 
15204 bool TOneRoute::SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID,
15205  TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndPosition, bool AutoSigsFlag, bool RecursiveCall)
15206 /*
15207  Brief: similar to SearchForPrefDir but with a PrefDirElement instead of a TrackElement & with additional parameters.
15208  PrefDirElement is the starting element from which to search, it is NOT stored in searchvector during this function. If it's an
15209  element that's not already in a route it will have been stored in SearchVector during GetPreferredRouteStartElement.
15210  ReqPosRouteID is used when RequiredPosition is start of an existing route, else it's -1.
15211  Return false if any element (apart from RequiredPosition) is on an existing route.
15212  Return false if not on a PrefDir with same ELink (can't check XLink as may not be set - if it's a leading point in a recursive call - see later).
15213 
15214  Detail: Function is a continuous loop as examine each element on a potential route, exiting only if find
15215  the required position (return true & leave Searchvector as set up) or if fail (erase all SearchVector entries
15216  added during the function so as to leave it exactly as it was on entering, then return false).
15217  It is a recursive function (similar to SearchForPrefDir) to enable all possible point branches to be searched.
15218  A VectorCount is maintained to count elements added to the SearchVector, so that this number can be erased on failure
15219  of any branch. Enter with starting PrefDirElement & XLinkPos for that element, RequiredPosition - the
15220  TrackVectorPosition of the element to be searched for, ReqPosRouteID -
15221  the route number that the searched-for element is the start of if any, and set to -1 if no
15222  such route. A pointer to EveryPrefDir is also passed in since this is not accessible directly from
15223  this unit, together with the ConsecSignalsRoute and AutoSigsFlag flags.
15224  Create 2 TPrefDirElements - PrefDirElement1 and 2, for use later - ELink has to match the preceding XLink, so the only
15225  2 possible PrefDirs are for a leading point & its two trailing PrefDirs.
15226 
15227  Enter loop - note that PrefDirElement changes each time round the loop - check if PrefDirElement XLinkPos faces buffers
15228  or a continuation, and fail if so. Check if reached a valid next signal in ConsecSignalsRoute on any but firstpass
15229  (nonrecursive firstpass starts at a valid signal, and recursive firstpass always starts at points so doesn't matter
15230  for recursive calls), and fail if so as user should always select the next signal in a route if ConsecSignals set.
15231  Create a new TPrefDirElement - SearchElement, from PrefDirElement.Conn[XLinkPos], & set all FixedTrackPiece &
15232  TrackElement values, ELink & ELinkPos, and also XLink & XLinkPos unless element is a leading point.
15233  Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
15234  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route),
15235  or if train on element (unless a bridge & train on different track).
15236  Check & fail for a fouled diagonal (unless element is a leading point - these checked later).
15237  Check element in EveryPrefDir with same ELink value & set PrefDirElement1, & also 2 if element is
15238  a leading point where both trailing directions are in EveryPrefDir, if not fail.
15239  Check if found RequiredPosition & that it's a signal/buffer/continuation. If OK save in SearchVector with
15240  AutoSignals member set if AutoSigsFlag set, then return true.
15241  Check & fail if a buffer or continuation (unless it is the RequiredPosition, in which case will have succeeded in the above check).
15242 
15243  Now check if a leading point and if so set XLinkPos to the 'set' exit & check if that XLink is in EveryPrefDir,
15244  by comparing with PrefDirElement1 or 2, fail if not. If valid check for a fouled diagonal and fail if so. If OK
15245  store element in SearchVector with AutoSignals member set if AutoSigsFlag set & do a recursive search using
15246  this element and XLinkPos, other parameters are passed in without change. If succeed return true, else erase the last element in
15247  SearchVector (i.e the earlier stored leading point element prior to doing the recursive search) & set XLinkPos to the 'unset' exit to
15248  check the other trailing direction. Then proceed in same way as above, i.e. fouled diagonal & recursive search etc. If
15249  fail on this XLinkPos then have tried & failed on both ways out from the leading point so erase the searchvector & return false.
15250 
15251  If not a leading point store the element (can only be PrefDirElement1 as not a leading point), then set
15252  up the next loop values of PrefDirElement & XLinkPos from SearchElement & NextXLinkPos and repeat the while loop.
15253 */
15254 
15255 {
15256  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPreferredRoute," + PrefDirElement.LogPrefDir() + "," +
15257  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString(EndPosition) + "," +
15258  AnsiString((short)AutoSigsFlag));
15259  int VectorCount = 0;
15260  TPrefDirElement PrefDirElement1, PrefDirElement2, BlankElement;
15261 
15262 // check for a fouled diagonal for first element. Added for v1.3.2
15263  if((PrefDirElement.XLink == 1) || (PrefDirElement.XLink == 3) || (PrefDirElement.XLink == 7) || (PrefDirElement.XLink == 9))
15264  {
15265  if(AllRoutes->DiagonalFouledByRouteOrTrain(0, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.XLink))
15266  {
15267  for(int x = 0; x < VectorCount; x++)
15268  {
15269  SearchVector.erase(SearchVector.end() - 1);
15270  }
15271  Utilities->CallLogPop(2043);
15272  return(false);
15273  }
15274  }
15275  bool FirstPass = true;
15276 
15277  while(true)
15278  {
15279  if(AutoSigsFlag && Track->IsLCAtHV(24, PrefDirElement.HLoc, PrefDirElement.VLoc))
15280  {
15281  Track->LCFoundInAutoSigsRoute = true;
15282  }
15283  if(Track->IsLCBarrierFlashingAtHV(1, PrefDirElement.HLoc, PrefDirElement.VLoc)) // can't set a route through a flashing barrier
15284  {
15285  for(int x = 0; x < VectorCount; x++)
15286  {
15287  SearchVector.erase(SearchVector.end() - 1);
15288  }
15289  Utilities->CallLogPop(1926);
15290  return(false);
15291  }
15292  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == End) // buffers or continuation
15293  {
15294  for(int x = 0; x < VectorCount; x++)
15295  {
15296  SearchVector.erase(SearchVector.end() - 1);
15297  }
15298  Utilities->CallLogPop(236);
15299  return(false);
15300  }
15301  if(!FirstPass && ConsecSignals && (PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal))
15302  // reached a valid signal that isn't the required position, user should always select the next
15303  // signal in a route so have to fail
15304  // won't affect recurive searches as for them the first pass element is always a point
15305  {
15306  for(int x = 0; x < VectorCount; x++)
15307  {
15308  SearchVector.erase(SearchVector.end() - 1);
15309  }
15310  Utilities->CallLogPop(237);
15311  return(false);
15312  }
15313  FirstPass = false;
15314  int NextPosition = PrefDirElement.Conn[XLinkPos];
15315  TTrackElement NextTrackElement = Track->TrackElementAt(88, NextPosition);
15316  TPrefDirElement SearchElement(NextTrackElement);
15317  SearchElement.TrackVectorPosition = NextPosition;
15318  int NextELinkPos = PrefDirElement.ConnLinkPos[XLinkPos];
15319  SearchElement.ELinkPos = NextELinkPos;
15320  SearchElement.ELink = SearchElement.Link[NextELinkPos]; // Note ELink isn't necessarily 10 - last XLink, as last element may have
15321  // been a gap. Now have all FixedTrackPiece & TrackElement values, + TrackVectorPosition, ELink & ELinkPos
15322  int NextXLinkPos;
15323  if(SearchElement.ELinkPos == 0)
15324  {
15325  NextXLinkPos = 1;
15326  }
15327  if(SearchElement.ELinkPos == 1)
15328  {
15329  NextXLinkPos = 0;
15330  }
15331  if(SearchElement.ELinkPos == 2)
15332  {
15333  NextXLinkPos = 3;
15334  }
15335  if(SearchElement.ELinkPos == 3)
15336  {
15337  NextXLinkPos = 2;
15338  }
15339  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
15340  {
15341  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
15342 // note that may be buffers, continuation or gap
15343  SearchElement.XLinkPos = NextXLinkPos;
15344  }
15345 
15346 // can't set XLink or XLinkPos yet if the element is a non-failed leading point.
15347 
15348 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
15349  for(unsigned int x = 0; x < SearchVector.size(); x++)
15350  {
15351  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
15352  {
15353  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
15354  // OK if a bridge & routes on different tracks
15355  {
15356  for(int x = 0; x < VectorCount; x++)
15357  {
15358  SearchVector.erase(SearchVector.end() - 1);
15359  }
15360  Utilities->CallLogPop(238);
15361  return(false);
15362  }
15363  }
15364  }
15365 
15366 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
15367  TAllRoutes::TRouteElementPair SecondPair;
15369  Track->TrackElementAt(89, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(90, SearchElement.TrackVectorPosition).VLoc, SecondPair);
15370  if(RoutePair.first > -1)
15371  {
15372  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
15373  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(12, RoutePair.first).GetFixedPrefDirElementAt(38,
15374  RoutePair.second).ELinkPos)))
15375  {
15376  // still OK if start of an expected route
15377  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(2, ReqPosRouteID)) || (RoutePair.second != 0))
15378  {
15379  for(int x = 0; x < VectorCount; x++)
15380  {
15381  SearchVector.erase(SearchVector.end() - 1);
15382  }
15383  Utilities->CallLogPop(239);
15384  return(false); // only allow for start of an expected route
15385  }
15386  }
15387  }
15388  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
15389  {
15390  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
15391  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(13, SecondPair.first).GetFixedPrefDirElementAt(39,
15392  SecondPair.second).ELinkPos)))
15393  {
15394  // still OK if start of an expected route
15395  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(3, ReqPosRouteID)) || (SecondPair.second != 0))
15396  {
15397  for(int x = 0; x < VectorCount; x++)
15398  {
15399  SearchVector.erase(SearchVector.end() - 1);
15400  }
15401  Utilities->CallLogPop(240);
15402  return(false); // only allow for start of an expected route
15403  }
15404  }
15405  }
15406 // check if a train on element, unless a bridge & train on different track
15407 // OK of same train as start element - no drop this
15408 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
15409  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
15410  {
15411  for(int x = 0; x < VectorCount; x++)
15412  {
15413  SearchVector.erase(SearchVector.end() - 1);
15414  }
15415  Utilities->CallLogPop(241);
15416  return(false);
15417  }
15418  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
15419  {
15420  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1))
15421  {
15422  for(int x = 0; x < VectorCount; x++)
15423  {
15424  SearchVector.erase(SearchVector.end() - 1);
15425  }
15426  Utilities->CallLogPop(242);
15427  return(false);
15428  }
15429  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1))
15430  {
15431  for(int x = 0; x < VectorCount; x++)
15432  {
15433  SearchVector.erase(SearchVector.end() - 1);
15434  }
15435  Utilities->CallLogPop(243);
15436  return(false);
15437  }
15438  }
15439 // check for a fouled diagonal (if not leading point - these checked later - leading point XLink == -1)
15440  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15441  {
15442  if(AllRoutes->DiagonalFouledByRouteOrTrain(7, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15443  {
15444  for(int x = 0; x < VectorCount; x++)
15445  {
15446  SearchVector.erase(SearchVector.end() - 1);
15447  }
15448  Utilities->CallLogPop(244);
15449  return(false);
15450  }
15451  }
15452 // check element in EveryPrefDir with same ELink (XLink may not be set) & save up to 2 elements (for leading point & 2 trailing PrefDirs)
15453 // note that point XLinks checked later, otherwise XLink fully defined by ELink so only need to check ELink
15454  bool InPrefDirFlag = false;
15455  PrefDirElement1 = BlankElement;
15456  PrefDirElement2 = BlankElement;
15457 
15458  bool FoundFlag;
15459  int PrefDirPos0 = -1;
15460  int PrefDirPos1 = -1;
15461  int PrefDirPos2 = -1;
15462  int PrefDirPos3 = -1;
15464  Track->TrackElementAt(92, SearchElement.TrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15465  int PrefDirVecPos[4] =
15466  {
15467  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
15468  };
15469  for(int x = 0; x < 4; x++)
15470  {
15471  int b = PrefDirVecPos[x];
15472  if((b > -1) && (EveryPrefDir->GetFixedPrefDirElementAt(40, b).ELink == SearchElement.ELink))
15473  {
15474  InPrefDirFlag = true;
15475  if(PrefDirElement1.TrackVectorPosition == -1)
15476  {
15477  PrefDirElement1 = EveryPrefDir->GetFixedPrefDirElementAt(41, b);
15478  }
15479  else
15480  {
15481  PrefDirElement2 = EveryPrefDir->GetFixedPrefDirElementAt(42, b);
15482  }
15483  }
15484  }
15485  if(!InPrefDirFlag)
15486  {
15487  for(int x = 0; x < VectorCount; x++)
15488  {
15489  SearchVector.erase(SearchVector.end() - 1);
15490  }
15491  Utilities->CallLogPop(245);
15492  return(false);
15493  }
15494 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
15495 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
15496 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
15498  {
15499  for(int x = 0; x < VectorCount; x++)
15500  {
15501  SearchVector.erase(SearchVector.end() - 1);
15502  }
15503  Utilities->CallLogPop(1690);
15504  return(false);
15505  }
15506 // check if found it
15507  if(SearchElement.TrackVectorPosition == RequiredPosition)
15508  {
15509 // need to ensure a signal/buffer/continuation
15510  if((SearchElement.Config[SearchElement.XLinkPos] != Signal) && (SearchElement.Config[SearchElement.XLinkPos] != End) &&
15511  (SearchElement.Config[SearchElement.XLinkPos] != Continuation))
15512  {
15513  TrainController->StopTTClockMessage(94, "Must select a valid signal, buffers or continuation"); //added at v2.7.0
15515  for(int x = 0; x < VectorCount; x++)
15516  {
15517  SearchVector.erase(SearchVector.end() - 1);
15518  }
15519  Utilities->CallLogPop(246);
15520  return(false);
15521  } // if((SearchElement.Config[SearchElement.XLinkPos] != Signal).......
15522 
15523  if(AutoSigsFlag)
15524  {
15525  PrefDirElement1.AutoSignals = true;
15526  }
15527  PrefDirElement1.PrefDirRoute = true;
15529  {
15531  {
15532  TrainController->StopTTClockMessage(76, "Can't create an automatic signal route through a level crossing");
15534  }
15535  for(int x = 0; x < VectorCount; x++)
15536  {
15537  SearchVector.erase(SearchVector.end() - 1);
15538  }
15539  Utilities->CallLogPop(1928);
15540  return(false);
15541  }
15542  SearchVector.push_back(PrefDirElement1); // must be 1 as it's a simple element
15543  VectorCount++; // not really needed but include for tidyness
15544  TotalSearchCount++;
15545  if(!RecursiveCall && SignalHasFailed(0)) //added at v2.13.0
15546  {
15547  for(int x = 0; x < VectorCount; x++)
15548  {
15549  SearchVector.erase(SearchVector.end() - 1);
15550  }
15551  Utilities->CallLogPop(2522);
15552  return(false);
15553  }
15554  Utilities->CallLogPop(247);
15555  return(true);
15556  } // if(SearchElement.TrackVectorPosition == RequiredPosition)
15557 
15558 // check if a buffer or continuation (end of search on this leg if not found by now)
15559  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
15560  {
15561  for(int x = 0; x < VectorCount; x++)
15562  {
15563  SearchVector.erase(SearchVector.end() - 1);
15564  }
15565  Utilities->CallLogPop(248);
15566  return(false);
15567  }
15568 // check if SearchVector exceeds a size of 150
15569  if(SearchVector.size() > 150)
15570  {
15571  for(int x = 0; x < VectorCount; x++)
15572  {
15573  SearchVector.erase(SearchVector.end() - 1);
15574  }
15575  Utilities->CallLogPop(1420);
15576  return(false);
15577  }
15578 //deal with failed points, added at v2.13.0
15579  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && Track->TrackElementAt(1518, SearchElement.TrackVectorPosition).Failed) //leading entry
15580  {
15581  if(Track->TrackElementAt(1519, SearchElement.TrackVectorPosition).Attribute == 0)
15582  {
15583  SearchElement.XLinkPos = 1;
15584  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
15585  PrefDirElement1.XLinkPos = 1; //need PrefDirElement1 set too as SearchElement set to it ready for next loop
15586  PrefDirElement1.XLink = SearchElement.Link[SearchElement.XLinkPos];
15587  PrefDirElement1.EntryExitNumber(); //to set EXNumber correctly as XLink might have changed for original
15588  }
15589  else
15590  {
15591  SearchElement.XLinkPos = 3;
15592  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
15593  PrefDirElement1.XLinkPos = 3; //need PrefDirElement1 set too as SearchElement set to it ready for next loop
15594  PrefDirElement1.XLink = SearchElement.Link[SearchElement.XLinkPos];
15595  PrefDirElement1.EntryExitNumber(); //to set EXNumber correctly as XLink might have changed for original
15596  }
15597  }
15598  else if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Trail) && Track->TrackElementAt(1520, SearchElement.TrackVectorPosition).Failed) //trailing entry
15599  {
15600  if((Track->TrackElementAt(1521, SearchElement.TrackVectorPosition).Attribute == 0) && (SearchElement.ELinkPos == 3)) //can't go any further
15601  {
15602  for(int x = 0; x < VectorCount; x++)
15603  {
15604  SearchVector.erase(SearchVector.end() - 1);
15605  }
15606  Utilities->CallLogPop(2514);
15607  return(false);
15608  }
15609  if((Track->TrackElementAt(1522, SearchElement.TrackVectorPosition).Attribute == 1) && (SearchElement.ELinkPos == 1)) //can't go any further
15610  {
15611  for(int x = 0; x < VectorCount; x++)
15612  {
15613  SearchVector.erase(SearchVector.end() - 1);
15614  }
15615  Utilities->CallLogPop(2515);
15616  return(false);
15617  }
15618  }
15619 // check if reached a non-failed leading point
15620  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && !Track->TrackElementAt(1523, SearchElement.TrackVectorPosition).Failed)
15621  {
15622 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
15623  int SearchPos1 = SearchElement.Attribute + 1;
15624  int SearchPos2;
15625  if(SearchPos1 == 2)
15626  {
15627  SearchPos1++;
15628  }
15629  if(SearchPos1 == 1)
15630  {
15631  SearchPos2 = 3;
15632  }
15633  else
15634  {
15635  SearchPos2 = 1;
15636  }
15637  SearchElement.XLink = SearchElement.Link[SearchPos1];
15638  SearchElement.XLinkPos = SearchPos1;
15639  InPrefDirFlag = false;
15640  if(SearchElement.XLink == PrefDirElement1.XLink)
15641  {
15642  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
15643  InPrefDirFlag = true;
15644  }
15645  else if(SearchElement.XLink == PrefDirElement2.XLink)
15646  {
15647  SearchElement = PrefDirElement2;
15648  InPrefDirFlag = true;
15649  }
15650 // push element with XLink set to position [SearchPos1] if on a PrefDir
15651  if(InPrefDirFlag)
15652  {
15653 // check for a fouled diagonal for leading point for XLinkPos == 1)
15654  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15655  {
15656  if(AllRoutes->DiagonalFouledByRouteOrTrain(1, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15657  {
15658  for(int x = 0; x < VectorCount; x++)
15659  {
15660  SearchVector.erase(SearchVector.end() - 1);
15661  }
15662  Utilities->CallLogPop(249);
15663  return(false);
15664  }
15665  }
15666  if(AutoSigsFlag)
15667  {
15668  SearchElement.AutoSignals = true;
15669  }
15670  SearchElement.PrefDirRoute = true;
15671  SearchVector.push_back(SearchElement);
15672  VectorCount++;
15673  TotalSearchCount++;
15674 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
15675  if(SearchForPreferredRoute(6, SearchElement, SearchPos1, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15676  AutoSigsFlag, true))
15677  {
15679  {
15681  {
15682  TrainController->StopTTClockMessage(77, "Can't create an automatic signal route through a level crossing");
15684  }
15685  for(int x = 0; x < VectorCount; x++)
15686  {
15687  SearchVector.erase(SearchVector.end() - 1);
15688  }
15689  Utilities->CallLogPop(1929);
15690  return(false);
15691  }
15692  if(!RecursiveCall && SignalHasFailed(1)) //added at v2.13.0
15693  {
15694  for(int x = 0; x < VectorCount; x++)
15695  {
15696  SearchVector.erase(SearchVector.end() - 1);
15697  }
15698  Utilities->CallLogPop(2523);
15699  return(false);
15700  }
15701  Utilities->CallLogPop(250);
15702  return(true);
15703  }
15704  else
15705  {
15706 // remove leading point with XLinkPos [1]
15707  SearchVector.erase(SearchVector.end() - 1);
15708  VectorCount--;
15709  }
15710  }
15711 // XLink set to position [SearchPos2]
15712  SearchElement.XLink = SearchElement.Link[SearchPos2];
15713  SearchElement.XLinkPos = SearchPos2;
15714  if(SearchElement.XLink == PrefDirElement1.XLink)
15715  {
15716  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
15717  }
15718  else if(SearchElement.XLink == PrefDirElement2.XLink)
15719  {
15720  SearchElement = PrefDirElement2;
15721  }
15722  else // failed to find a valid exit from the point
15723  {
15724  for(int x = 0; x < VectorCount; x++)
15725  {
15726  SearchVector.erase(SearchVector.end() - 1);
15727  }
15728  Utilities->CallLogPop(251);
15729  return(false);
15730  }
15731 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
15732  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15733  {
15734  if(AllRoutes->DiagonalFouledByRouteOrTrain(2, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15735  {
15736  for(int x = 0; x < VectorCount; x++)
15737  {
15738  SearchVector.erase(SearchVector.end() - 1);
15739  }
15740  Utilities->CallLogPop(252);
15741  return(false);
15742  }
15743  }
15744 // push element with XLink set to position [SearchPos2]
15745  if(AutoSigsFlag)
15746  {
15747  SearchElement.AutoSignals = true;
15748  }
15749  SearchElement.PrefDirRoute = true;
15750  SearchVector.push_back(SearchElement);
15751  VectorCount++;
15752  TotalSearchCount++;
15753 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
15754  if(SearchForPreferredRoute(7, SearchElement, SearchPos2, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15755  AutoSigsFlag, true))
15756  {
15758  {
15760  {
15761  TrainController->StopTTClockMessage(78, "Can't create an automatic signal route through a level crossing");
15763  }
15764  for(int x = 0; x < VectorCount; x++)
15765  {
15766  SearchVector.erase(SearchVector.end() - 1);
15767  }
15768  Utilities->CallLogPop(1930);
15769  return(false);
15770  }
15771  if(!RecursiveCall && SignalHasFailed(2)) //added at v2.13.0
15772  {
15773  for(int x = 0; x < VectorCount; x++)
15774  {
15775  SearchVector.erase(SearchVector.end() - 1);
15776  }
15777  Utilities->CallLogPop(2524);
15778  return(false);
15779  }
15780  Utilities->CallLogPop(1592);
15781  return(true);
15782  }
15783  else
15784  {
15785  for(int x = 0; x < VectorCount; x++)
15786  {
15787  SearchVector.erase(SearchVector.end() - 1);
15788  }
15789  Utilities->CallLogPop(253);
15790  return(false);
15791  }
15792  } // if leading point
15793 
15794 // here if ordinary element or failed points, push it, inc vector & update PrefDirElement ready for next element on PrefDir
15795  SearchElement = PrefDirElement1;
15796  if(AutoSigsFlag)
15797  {
15798  SearchElement.AutoSignals = true;
15799  }
15800  SearchElement.PrefDirRoute = true;
15801  SearchVector.push_back(SearchElement);
15802  VectorCount++;
15803  TotalSearchCount++;
15804  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
15805  PrefDirElement = SearchElement;
15806  } // while(true)
15807 }
15808 
15809 // ---------------------------------------------------------------------------
15810 
15811 void TOneRoute::ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
15812 {
15813 /*
15814  For routes, as opposed to PrefDirs, the new route elements are first entered into SearchVector,
15815  and the new or extended route created from that. Hence action varies depending on whether
15816  it is a completely new route, or an extension of an existing route at the beginning or the end.
15817  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
15818  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
15819 
15820  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
15821  Check if route end selection is in an existing route (ReqPosRouteID > -1), and if so proceed as follows:-
15822  if both new and existing routes non-autosig, add the old route to the SearchVector then delete the old route;
15823  if both new and existing routes autosig, add the old route to the SearchVector then delete the old route;
15824  in both the above cases if RequPosRouteNumber is less than StartSelectionRouteNumber then StartSelectionRouteNumber
15825  is decremented;
15826  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element)
15827  from the existing route, then enter the new route into the AllRoutesVector;
15828  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
15829  then enter the new route into the AllRoutesVector.
15830 
15831  Check if StartSelectionRouteID set (extending an existing route) and if so proceed as follows:-
15832  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector);
15833  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector);
15834  in both the above cases validate the extended route, then call SetRoutePoints & SetRouteSignals for the extended route and return.
15835  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
15836  then add it to the start of the new route, then check its validity, enter it into the AllRoutesVector, call SetRoutePoints & SetRouteSignals
15837  for the new route and return;
15838  if new route non-autosig and existing route autosig, leave the existing route as it is, check its validity, then just enter the new
15839  route into the AllRoutesVector, finally call SetRoutePoints & SetRouteSignals for the new route and return.
15840 
15841  If not returned by now the route in SearchVector is to be added as a new route, so check its validity, create a new route using
15842  StoreOneRoute, call SetRoutePoints & SetRouteSignals and return. In practice the validity check, storage into AllRoutesVector and
15843  SetRoutePoints & SetRouteSignals call are combined for the above three cases.
15844 
15845 */
15846  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddPreferredRouteSearchVector," +
15847  AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString((short)AutoSigsFlag));
15848  if(SearchVector.size() < 1)
15849  {
15850  Utilities->CallLogPop(254);
15851  return;
15852  }
15854  if(!ValidatePrefDir(3)) // check the new route elements in SearchVector
15855  {
15856  Utilities->CallLogPop(255);
15857  return;
15858  }
15859  TAllRoutes::TLockedRouteClass LockedRouteObject;
15860 
15862  unsigned int TruncatePrefDirPosition = 0;
15863 
15864  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartRouteNumber as would have failed in GetNextRouteElement
15865 /* if have ReqPosRouteID:
15866  if both new and existing routes non-autosig, then add the old route to the SearchVector then delete the old route
15867  if both new and existing routes autosig, then add the old route to the SearchVector then delete the old route
15868  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element) from
15869  the existing route, then enter the new route into the AllRoutesVector
15870  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
15871  then enter the new route into the AllRoutesVector
15872 */
15873  {
15876  {
15877  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(21, ReqPosRouteID).PrefDirSize();
15878  x++) // start at 1 as first element already in SearchVector
15879  {
15881  }
15882  // note that route numbers in map adjusted when ReqPos route cleared
15884  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
15885  // set during ClearRouteDuringRouteBuildingAt
15887  {
15890  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
15891  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
15892  }
15893  }
15895  {
15897  AllRoutes->RemoveRouteElement(3, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
15898  }
15900  {
15901  SearchVector.pop_back();
15902  }
15903  }
15904  if(StartSelectionRouteID > -1)
15905 /* if have StartSelectionRouteID:
15906  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector)
15907  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector)
15908  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
15909  then add it to the start of the new route, then enter the new route into the AllRoutesVector
15910  if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
15911 */
15912  {
15914  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
15915  {
15918  {
15919  int RouteNumber = AllRoutes->GetRouteVectorNumber(0, StartSelectionRouteID);
15920  for(unsigned int x = 0; x < SearchVector.size(); x++)
15921  {
15923  RouteNumber, GetFixedSearchElementAt(3, x));
15924  // find & store locked route truncate position in PrefDirVector for later use
15926  {
15927  if(GetFixedSearchElementAt(15, x).TrackVectorPosition == int(AllRoutes->LockedRouteTruncateTrackVectorPosition))
15928  {
15929  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(172, RouteNumber).PrefDirSize() - 1;
15930  }
15931  }
15932  }
15934  {
15935  throw Exception("Error - failed to validate extended route for preferred route");
15936  }
15939  if(!AutoSigsFlag)
15940  {
15941  AllRoutes->GetModifiableRouteAtIDNumber(7, StartSelectionRouteID).SetLCChangeValues(0, true); // ConsecSignalsRoute is true
15942  }
15943  // now add the reinstated locked route if required and set signals accordingly
15945  {
15946  LockedRouteObject.RouteNumber = RouteNumber;
15947  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
15948  // now reset the signals for the locked route
15949  AllRoutes->SetAllRearwardsSignals(9, 0, RouteNumber, TruncatePrefDirPosition);
15950  for(int c = AllRoutes->GetFixedRouteAt(173, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
15951  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
15952  {
15953  // return all signals to red in route section to be truncated
15954  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(174, RouteNumber).PrefDirVector.at(c);
15955  TTrackElement & TrackElement = Track->TrackElementAt(812, PrefDirElement.TrackVectorPosition);
15956  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
15957  {
15958  TrackElement.Attribute = 0;
15959  Track->PlotSignal(10, TrackElement, Display);
15960  Display->PlotOutput(113, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
15961  Display->PlotOutput(114, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
15962  }
15963  }
15964  }
15965  AllRoutes->CheckMapAndRoutes(1); // test
15966  Utilities->CallLogPop(256);
15967  return;
15968  }
15970  {
15973  RouteElement.AutoSignals = true;
15974  RouteElement.EXGraphicPtr = RouteElement.GetRouteGraphicPtr(AutoSigsFlag, true);
15975  RouteElement.EntryDirectionGraphicPtr = RouteElement.GetDirectionRouteGraphicPtr(AutoSigsFlag, true); // as above
15976  AllRoutes->RemoveRouteElement(4, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
15977  SearchVector.insert(SearchVector.begin(), 1, RouteElement);
15978  }
15979  }
15980  else
15981  {
15983  }
15984 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the
15985 // AllRoutesVector hence nothing to do here
15986  }
15987  PrefDirVector = SearchVector; // need to copy again since SearchVector may have been extended
15988  if(!ValidatePrefDir(5)) // validate PrefDir for all new route elements
15989  {
15990  throw Exception("Error - failed to validate single route for preferred route");
15991  }
15992  AllRoutes->StoreOneRoute(1, this);
15993  AllRoutes->GetModifiableRouteAt(3, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(1); // new addition
15994  AllRoutes->GetModifiableRouteAt(16, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(5); // new addition
15995  if(!AutoSigsFlag)
15996  {
15997  AllRoutes->GetModifiableRouteAt(18, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(1, true); // ConsecSignalsRoute is true
15998  }
15999  AllRoutes->CheckMapAndRoutes(2); // test
16000  Utilities->CallLogPop(257);
16001 }
16002 
16003 // ---------------------------------------------------------------------------
16004 
16005 bool TOneRoute::GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon) // Return true if OK.
16006 {
16007 /*
16008  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
16009  Clear the PrefDir and search vectors using ClearRoute(). Check selection matches a TrackElement
16010  & ensure signal/buffers/continuation.
16011  Note that can't select ConsecSignalsRoute for non-preferred routes.
16012  Check if train on element & disallow.
16013  Set default values for retained parameters:-
16014  StartRoutePosition = TrackVectorPosition of the element to be used as the start of the route;
16015  StartSelectionRouteID = route that selection starts in if there is one;
16016 
16017  Create 2 PrefDirElements from the TrackElement, setting all values corresponding to the 2 possible PrefDirs
16018  through the element (can only be 2 as 3 & 4 ended elements aren't allowed) & make an EXNumber check for
16019  validity. This is just for safety reasons, the PrefDir values aren't used.
16020  StartElement1 & 2 are set to these PrefDirelements.
16021 
16022  There is no need to check that the element lies in a PrefDir for nonpreferred selections.
16023 
16024  Check if in an existing route & if so only allow last element to be selected - ensure it has somewhere to go!
16025  Set StartElement1, StartSelectionRouteID and StartRoutePosition to correspond to the route end element and
16026  blank StartElement2 (only want to use the route element), then return true.
16027  Check if adjacent to start or end of an existing route & disallow if so.
16028  If not in a route and not failed so far then reset all Link, all LinkPos, & EXNumber values to -1, and CheckCount
16029  to 4 for StartElement1, & blank StartElement2. The remaining data members will be set later in
16030  SetRemainingSearchVectorValues().
16031  Finally add the required element to the SearchVector & return true.
16032 
16033 */
16034  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNonPreferredRouteStartElement," + AnsiString(HLoc) + "," +
16035  AnsiString(VLoc) + "," + AnsiString((short)Callon));
16036  ClearRoute();
16037  int TrackVectorPosition;
16038  TTrackElement TrackElement;
16039  TPrefDirElement FirstElement, LastElement;
16040 
16041  if(!(Track->FindNonPlatformMatch(9, HLoc, VLoc, TrackVectorPosition, TrackElement)))
16042  {
16043  Utilities->CallLogPop(258);
16044  return(false);
16045  }
16046  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
16047  {
16048  if(!Callon)
16049  {
16050  TrainController->StopTTClockMessage(34, "Can't select points, bridge or crossover when route building");
16051  }
16052 // makes later adjacent route checks too complicated
16053  Utilities->CallLogPop(259);
16054  return(false);
16055  }
16056  if(Track->IsLCAtHV(21, HLoc, VLoc))
16057  {
16058  TrainController->StopTTClockMessage(74, "Can't start a route on a level crossing");
16059  Utilities->CallLogPop(1910);
16060  return(false);
16061  }
16062 // check if selected a train & disallow if so
16063  if(TrackElement.TrainIDOnElement > -1)
16064  {
16065  if(!Callon)
16066  {
16067  TrainController->StopTTClockMessage(35, "Can't start a route on a train");
16068  }
16069  Utilities->CallLogPop(260);
16070  return(false);
16071  }
16072 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
16073  TPrefDirElement PrefDirElement;
16074  int LockedVectorNumber;
16075 
16076  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(3, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
16077  {
16078  if(!Callon)
16079  {
16080  TrainController->StopTTClockMessage(36, "Can't start a route on a locked route");
16081  }
16082  Utilities->CallLogPop(261);
16083  return(false);
16084  }
16085  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(4, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
16086  {
16087  if(!Callon)
16088  {
16089  TrainController->StopTTClockMessage(37, "Can't start a route on a locked route");
16090  }
16091  Utilities->CallLogPop(262);
16092  return(false);
16093  }
16095 // AdjacentStartRouteNumber = -1;
16096  StartRoutePosition = TrackVectorPosition;
16097 // StartRouteSelectPosition = TrackVectorPosition;
16098 
16099  TPrefDirElement PrefDirElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
16100  TPrefDirElement PrefDirElement2(TrackElement);
16101 
16102  PrefDirElement1.TrackVectorPosition = TrackVectorPosition;
16103  PrefDirElement2.TrackVectorPosition = TrackVectorPosition;
16104  TPrefDirElement BlankElement;
16105 
16106  PrefDirElement1.ELinkPos = 0;
16107  PrefDirElement1.XLinkPos = 1;
16108  PrefDirElement1.ELink = PrefDirElement1.Link[0];
16109  PrefDirElement1.XLink = PrefDirElement1.Link[1];
16110  if(!(PrefDirElement1.EntryExitNumber()))
16111  {
16112  throw Exception("Error, No EXNumber for PrefDirElement1 in GetNonPreferredRouteStartElement");
16113  // no need for bridge check as bridge selections not allowed
16114  }
16115  PrefDirElement1.CheckCount = 9;
16116  PrefDirElement2.ELinkPos = 1;
16117  PrefDirElement2.XLinkPos = 0;
16118  PrefDirElement2.ELink = PrefDirElement2.Link[1];
16119  PrefDirElement2.XLink = PrefDirElement2.Link[0];
16120  if(!(PrefDirElement2.EntryExitNumber()))
16121  {
16122  throw Exception("Error, No EXNumber for PrefDirElement2 in GetNonPreferredRouteStartElement");
16123  }
16124  PrefDirElement2.CheckCount = 9; // both now set
16125 
16126 // set StartElements to the above PrefDirElements
16127  StartElement1 = PrefDirElement1;
16128  StartElement2 = PrefDirElement2;
16129 
16130 // no PrefDir check needed as doesn't need to be in a PrefDir
16131 
16132 // look for exact match in a route first - can't be a 3 or 4 track element so only need to look for one TRouteElementPair
16134  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(1, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
16135 
16136  if(RoutePair.first > -1)
16137  {
16138  if(RoutePair.second != AllRoutes->GetFixedRouteAt(31, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
16139  {
16140  if(!Callon)
16141  {
16142  TrainController->StopTTClockMessage(38, "Can't start a route within or at the start of an existing route");
16143  }
16144  Utilities->CallLogPop(263);
16145  return(false);
16146  }
16147  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(32, RoutePair.first).GetFixedPrefDirElementAt(56, RoutePair.second);
16148  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
16149  {
16150  if(!Callon)
16151  {
16152  TrainController->StopTTClockMessage(39, "No forward connection from this position");
16153  }
16154  Utilities->CallLogPop(264);
16155  return(false);
16156  }
16157  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(11, RouteElement.Conn[RouteElement.XLinkPos],
16158  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
16159  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
16160  {
16161  if(!Callon)
16162  {
16163  TrainController->StopTTClockMessage(40, "Can't start a route at an element that links forward into an existing route");
16164  }
16165  Utilities->CallLogPop(265);
16166  return(false);
16167  }
16168  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(162, RoutePair.first).RouteID);
16170  AllRoutes->GetFixedRouteAt(34, RoutePair.first).PrefDirSize() - 1); // last element
16171  StartElement2 = BlankElement; // only use the route element
16173  Utilities->CallLogPop(266);
16174  return(true); // all retained values set
16175  }
16176 
16177  else // selection not in an existing route
16178  {
16179 // check if it's adjacent to start of an an existing route,
16180  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
16181  {
16182  FirstElement = AllRoutes->GetFixedRouteAt(35, a).GetFixedPrefDirElementAt(58, 0);
16183  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
16184  {
16185  if(!Callon)
16186  {
16187  TrainController->StopTTClockMessage(41, "Can't make selection adjacent to start of another route");
16188  }
16189  Utilities->CallLogPop(267);
16190  return(false);
16191  }
16192  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
16193  {
16194  if(!Callon)
16195  {
16196  TrainController->StopTTClockMessage(42, "Can't make selection adjacent to start of another route");
16197  }
16198  Utilities->CallLogPop(268);
16199  return(false);
16200  }
16201  }
16202 // check if it's adjacent to end of an an existing route,
16203  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
16204  {
16206  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
16207  {
16208  if(!Callon)
16209  {
16210  TrainController->StopTTClockMessage(43, "Can't start a route adjacent to the end of an existing route");
16211  }
16212  Utilities->CallLogPop(269);
16213  return(false);
16214  }
16215  }
16216  // not in a route or adjacent to start or end of a route
16217  // in this case reset all variable values to -1 & CheckCount to 4
16218  StartElement1.ELink = -1;
16219  StartElement1.ELinkPos = -1;
16220  StartElement1.XLink = -1;
16221  StartElement1.XLinkPos = -1;
16222  StartElement1.EXNumber = -1;
16224  StartElement2 = BlankElement;
16225  SearchVector.push_back(StartElement1);
16226  Utilities->CallLogPop(270);
16227  return(true);
16228  }
16229 }
16230 
16231 // ---------------------------------------------------------------------------
16232 bool TOneRoute::GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
16233 
16234 /*
16235  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
16236 
16237  Declare the following integers:-
16238  EndPosition - TrackVectorPosition for the selection;
16239  ReqPosRouteID - for the existing route selected if there is one, set to -1 if not;
16240  Check if selection is a valid track element and set EndPosition.
16241  Cancel if select original start element, then check that not points, bridge or crossover.
16242  Check & fail if a train is present at the selection.
16243  Create & set 2 PrefDirElements EndElement1 & 2 corresponding to the 2 possible PrefDir elements (similar to StartElement1 & 2
16244  in GetNonPreferredRouteStartElement) & make an EXNumber validity check just for safety reasons - the PrefDir values are not used.
16245  No check needed for selection in EveryPrefDir.
16246  Check if selection in an existing route & if so ensure it's the start element and that it doesn't have an 'End' facing the start.
16247  If it is the start of a route set ReqPosRouteID, EndPosition & EndElement1 to the start of route values and blank EndElement2
16248  as don't need it if in a route.
16249  Check if selection adj to start or end of a route and disallow.
16250  Fail if select same route as starting route, though should already have failed earlier if this is so.
16251 
16252  If there's a StartSelectionRouteID then StartElement1 will be set to
16253  the last entry in the selected route so use SearchForNonPreferredRoute to search for the selected end element from this
16254  start element. If succeed then complete the search vector values (since not on a PrefDir) & return true, for Interface
16255  to handle the flashing & time delay. After the delay completes the Interface flasher calls ConvertAndAddNonPreferredRouteSearchVector
16256  to add the new route to the AllRoutesVectorPtr.
16257  If no starting route then StartElement1 only has basic values set & is in the SearchVector, and StartElement2 is blank.
16258  Check if the selected element is adjacent to the starting position and if so set the route to go directly to it (as opposed to
16259  going round a long loop to get to it just because that XLinkPos happens to be chosen first).
16260  If not adjacent then search on the two possible ways out of StartElement1 providing it isn't facing an 'End'. If succeed complete
16261  the search vector values and return.
16262  If not returned yet then have failed to find the required element so return false with no message.
16263 
16264 */
16265 
16266 {
16267 // get EndPosition
16268  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextNonPreferredRouteElement," + AnsiString(HLoc) + "," +
16269  AnsiString(VLoc));
16270  int EndPosition;
16271  int NewFailedPointsTVPos = -1; //added at v2.13.0 for point failures
16272 
16273  TotalSearchCount = 0;
16274  ReqPosRouteID = IDInt(-1); // for not used
16275  TTrackElement TrackElement;
16276  TPrefDirElement BlankElement;
16278 
16279  if(!(Track->FindNonPlatformMatch(10, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
16280  {
16281  Utilities->CallLogPop(271);
16282  return(false);
16283  }
16284 // EndPosition = EndSelectPosition;
16285 // cancel selection if on original start element
16286  if(EndPosition == StartRoutePosition)
16287  {
16288  Utilities->CallLogPop(272);
16289  return(false);
16290  }
16291  if(Track->IsLCAtHV(22, HLoc, VLoc))
16292  {
16293  TrainController->StopTTClockMessage(75, "Can't end a route on a level crossing");
16294  Utilities->CallLogPop(1911);
16295  return(false);
16296  }
16297  if((TrackElement.TrackType == Points) && !Callon)
16298  {
16299  if(!Callon)
16300  {
16301  TrainController->StopTTClockMessage(44, "Can't select points, bridge or crossover when route building");
16302  }
16303 // makes later adjacent route checks too complicated
16304  Utilities->CallLogPop(273);
16305  return(false);
16306  }
16307  if((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
16308  {
16309  if(!Callon)
16310  {
16311  TrainController->StopTTClockMessage(71, "Can't select points, bridge or crossover when route building");
16312  }
16313 // makes later adjacent route checks too complicated
16314  Utilities->CallLogPop(1861);
16315  return(false);
16316  }
16317 // check if train on element
16318  if(TrackElement.TrainIDOnElement > -1)
16319  {
16320  if(!Callon)
16321  {
16322  TrainController->StopTTClockMessage(45, "Can't end a route on a train");
16323  }
16324  Utilities->CallLogPop(274);
16325  return(false);
16326  }
16327 // set the 2 EndElements corresponding to the 2 possible PrefDirs for the selected element (for safety reasons - to ensure EXNumber validity
16328 // check passed)
16329  TPrefDirElement EndElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
16330  TPrefDirElement EndElement2(TrackElement);
16331 
16332  EndElement1.TrackVectorPosition = EndPosition;
16333  EndElement2.TrackVectorPosition = EndPosition;
16334  EndElement1.ELinkPos = 0;
16335  EndElement1.XLinkPos = 1;
16336  EndElement1.ELink = EndElement1.Link[0];
16337  EndElement1.XLink = EndElement1.Link[1];
16338  if(!(EndElement1.EntryExitNumber()))
16339  {
16340  throw Exception("Error, No EXNumber for EndElement1 in GetNonPreferredRouteStartElement");
16341  }
16342  EndElement1.CheckCount = 9;
16343  EndElement2.ELinkPos = 1;
16344  EndElement2.XLinkPos = 0;
16345  EndElement2.ELink = EndElement2.Link[1];
16346  EndElement2.XLink = EndElement2.Link[0];
16347  if(!(EndElement2.EntryExitNumber()))
16348  {
16349  throw Exception("Error, No EXNumber for EndElement2 in GetNonPreferredRouteStartElement");
16350  }
16351  EndElement2.CheckCount = 9; // both now set
16352 
16353 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
16354 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
16355 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
16356 
16357  if(EndElement1.HLoc >= StartElement1.HLoc)
16358  {
16360  SearchLimitHighH = EndElement1.HLoc + 15;
16361  }
16362  else
16363  {
16364  SearchLimitLowH = EndElement1.HLoc - 15;
16366  }
16367  if(EndElement1.VLoc >= StartElement1.VLoc)
16368  {
16370  SearchLimitHighV = EndElement1.VLoc + 15;
16371  }
16372  else
16373  {
16374  SearchLimitLowV = EndElement1.VLoc - 15;
16376  }
16377 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
16378  check & TotalSearchCounts check
16379  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
16380  {
16381  if(!Callon) TrainController->StopTTClockMessage(66, "Unable to reach the selected element - too far ahead");
16382  Utilities->CallLogPop(1694);
16383  return false;
16384  }
16385 */
16386 // don't need EveryPrefDir check for NonPreferredRoute
16387 
16388 // check if in an existing route - can't be a 3 or 4 track element so only one TRouteElementPair to be set
16389 // bool InRoute = false;
16391  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(2, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
16392 
16393  if(RoutePair.first > -1)
16394  {
16395  if(RoutePair.second != 0) // not first element in existing route so no good
16396  {
16397  if(!Callon)
16398  {
16399  TrainController->StopTTClockMessage(46, "Can't end a route within or at the end of an existing route");
16400  }
16401  Utilities->CallLogPop(275);
16402  return(false);
16403  }
16404  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(38, RoutePair.first).GetFixedPrefDirElementAt(60, RoutePair.second);
16405 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
16406  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(12, RouteElement.Conn[RouteElement.ELinkPos],
16407  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
16408  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
16409  {
16410  if(!Callon)
16411  {
16412  TrainController->StopTTClockMessage(47, "Can't start a route within or at the end of an existing route");
16413  }
16414  Utilities->CallLogPop(276);
16415  return(false);
16416  }
16417  EndElement1 = AllRoutes->GetFixedRouteAt(39, RoutePair.first).GetFixedPrefDirElementAt(61, 0);
16418  EndElement2 = BlankElement; // only need the route element
16419  EndPosition = EndElement1.TrackVectorPosition;
16420  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(161, RoutePair.first).RouteID);
16421  }
16422 // check if adjacent to start of an existing route and disallow (unless start of existing route is also the start of this route)
16423  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
16424  {
16425  int AdjPosition = AllRoutes->GetFixedRouteAt(40, a).GetFixedPrefDirElementAt(62, 0).TrackVectorPosition;
16426  int AdjLinkPos = AllRoutes->GetFixedRouteAt(219, a).GetFixedPrefDirElementAt(245, 0).ELinkPos; // added at v1.3.1
16427 // if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
16428 // && (AdjPosition != StartRoutePosition))
16429  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
16430  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
16431  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos) && (AdjPosition != StartRoutePosition))
16432  {
16433  if(!Callon)
16434  {
16435  TrainController->StopTTClockMessage(48, "Can't end a route adjacent to the start of an existing route");
16436  }
16437  Utilities->CallLogPop(277);
16438  return(false);
16439  }
16440 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
16441 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (AdjPosition != StartRoutePosition))
16442  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
16443  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
16444  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos) &&
16445  (AdjPosition != StartRoutePosition))
16446  {
16447  if(!Callon)
16448  {
16449  TrainController->StopTTClockMessage(49, "Can't end a route adjacent to the start of an existing route");
16450  }
16451  Utilities->CallLogPop(278);
16452  return(false);
16453  }
16454 // check if adjacent to end of a route & disallow (unless end of existing route is the start of this route - i.e. extending route by 1 element)
16456  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition) &&
16457  (EndOfRouteElement.TrackVectorPosition != StartRoutePosition))
16458  {
16459  if(!Callon)
16460  {
16461  TrainController->StopTTClockMessage(50, "Can't end a route adjacent to the end of an existing route");
16462  }
16463  Utilities->CallLogPop(279);
16464  return(false);
16465  }
16466  }
16467 
16468 // check for same route as start element
16470  {
16471  if(!Callon)
16472  {
16473  TrainController->StopTTClockMessage(51, "Can't select same route as started in");
16474  }
16475  Utilities->CallLogPop(280);
16476  return(false);
16477  }
16478 // check for a looping route
16479  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
16480  {
16482  {
16483  if(!Callon)
16484  {
16485  TrainController->StopTTClockMessage(70, "Can't create a route that loops back on itself");
16486  }
16487  Utilities->CallLogPop(1845);
16488  return(false);
16489  }
16490  }
16491 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
16492 // so search from this element.
16493 
16494  TTrackElement &TempElement1 = StartElement1; // this needed to avoid a TTrackElement construction ambiguity in later search function
16495 
16496  if(StartSelectionRouteID > -1)
16497  {
16498  if(SearchForNonPreferredRoute(0, TempElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, false))
16499  {
16501  if(PointsToBeChanged(0, NewFailedPointsTVPos))
16502  {
16503  if(NewFailedPointsTVPos > -1)
16504  {
16505  TTrackElement TE = Track->TrackElementAt(1494, NewFailedPointsTVPos);
16506  TrainController->StopTTClockMessage(113, "Points at " + TE.ElementID +
16507  " failed during route setting.\nTry to find a different route.");
16508  Utilities->CallLogPop(2504);
16509  return(false);
16510  }
16511  PointsChanged = true;
16512  }
16513  Utilities->CallLogPop(281);
16514  return(true);
16515  }
16516  else
16517  {
16518  if(!Callon && !Track->SuppressRouteFailMessage)
16519  {
16521  }
16522  Utilities->CallLogPop(282);
16523  return(false);
16524  }
16525  }
16526  else // no starting route, so StartElement1 only has basic values set & is in SearchVector, StartElement2 is blank
16527  // search on the 2 ways out of the element, which has to be a 2-ended element
16528  {
16529 // check if selection adjacent to start element and if so use that
16530  if(SearchVector.at(0).Conn[0] == EndPosition)
16531  {
16532  if(SearchForNonPreferredRoute(1, TempElement1, 0, EndPosition, ReqPosRouteID, false))
16533  {
16535  if(PointsToBeChanged(1, NewFailedPointsTVPos))
16536  {
16537  if(NewFailedPointsTVPos > -1)
16538  {
16539  TTrackElement TE = Track->TrackElementAt(1496, NewFailedPointsTVPos);
16540  TrainController->StopTTClockMessage(115, "Points at " + TE.ElementID +
16541  " failed during route setting.\nTry to find a different route.");
16542  Utilities->CallLogPop(2506);
16543  return(false);
16544  }
16545  PointsChanged = true;
16546  }
16547  Utilities->CallLogPop(283);
16548  return(true);
16549  }
16550  else
16551  {
16552  if(!Callon && !Track->SuppressRouteFailMessage)
16553  {
16555  }
16556  Utilities->CallLogPop(284);
16557  return(false);
16558  }
16559  }
16560  else if(SearchVector.at(0).Conn[1] == EndPosition)
16561  {
16562  if(SearchForNonPreferredRoute(2, TempElement1, 1, EndPosition, ReqPosRouteID, false))
16563  {
16565  if(PointsToBeChanged(2, NewFailedPointsTVPos))
16566  {
16567  if(NewFailedPointsTVPos > -1)
16568  {
16569  TTrackElement TE = Track->TrackElementAt(1498, NewFailedPointsTVPos);
16570  TrainController->StopTTClockMessage(117, "Points at " + TE.ElementID +
16571  " failed during route setting.\nTry to find a different route.");
16572  Utilities->CallLogPop(2508);
16573  return(false);
16574  }
16575  PointsChanged = true;
16576  }
16577  Utilities->CallLogPop(285);
16578  return(true);
16579  }
16580  else
16581  {
16582  if(!Callon && !Track->SuppressRouteFailMessage)
16583  {
16585  }
16586  Utilities->CallLogPop(286);
16587  return(false);
16588  }
16589  }
16590  // now start off in the best direction
16591  int BestPos = Track->FindClosestLinkPosition(1, StartRoutePosition, EndPosition); // can only be 0 or 1
16592 
16593  if(SearchVector.at(0).Config[BestPos] != End)
16594  {
16595  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
16596  if(SearchForNonPreferredRoute(3, TempElement1, BestPos, EndPosition, ReqPosRouteID, false))
16597  {
16599  if(PointsToBeChanged(3, NewFailedPointsTVPos))
16600  {
16601  if(NewFailedPointsTVPos > -1)
16602  {
16603  TTrackElement TE = Track->TrackElementAt(1500, NewFailedPointsTVPos);
16604  TrainController->StopTTClockMessage(119, "Points at " + TE.ElementID +
16605  " failed during route setting.\nTry to find a different route.");
16606  Utilities->CallLogPop(2510);
16607  return(false);
16608  }
16609  PointsChanged = true;
16610  }
16611  Utilities->CallLogPop(287);
16612  return(true);
16613  }
16614  }
16615  if(SearchVector.at(0).Config[1 - BestPos] != End)
16616  {
16617  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
16618  if(SearchForNonPreferredRoute(4, TempElement1, (1 - BestPos), EndPosition, ReqPosRouteID, false))
16619  {
16621  if(PointsToBeChanged(4, NewFailedPointsTVPos))
16622  {
16623  if(NewFailedPointsTVPos > -1)
16624  {
16625  TTrackElement TE = Track->TrackElementAt(1502, NewFailedPointsTVPos);
16626  TrainController->StopTTClockMessage(121, "Points at " + TE.ElementID +
16627  " failed during route setting.\nTry to find a different route.");
16628  Utilities->CallLogPop(2512);
16629  return(false);
16630  }
16631  PointsChanged = true;
16632  }
16633  Utilities->CallLogPop(288);
16634  return(true);
16635  }
16636  }
16637  }
16638  if(!Callon && !Track->SuppressRouteFailMessage)
16639  {
16641  }
16642  Utilities->CallLogPop(289);
16643  return(false);
16644 }
16645 
16646 // ---------------------------------------------------------------------------
16647 
16648 bool TOneRoute::SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, bool RecursiveCall)
16649 /*
16650  This is very similar to the preferred route search, but without the need to ensure all elements are in EveryPrefDir.
16651  Returns true for successful search with SearchVector containing the new route elements. Enter with CurrentTrackElement
16652  stored in SearchVector unless it's in an existing route, & XLinkPos set to the link to search on.
16653  Keep a count of entries in SearchVector during the current function call, so that this number can be
16654  erased for an unproductive branch search.
16655  First check (within the loop) whether XLink leads to an End & return false if so.
16656  Create a NextTrackElement from Current & XLinkPos, and a PrefDirElement (SearchElement) from that, setting as many values as
16657  possible. Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
16658  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route), if
16659  train on element (unless a bridge & train on different track), or if element
16660  fouls an existing diagonal route (except if element is a leading point - these checked later).
16661  Then check if found required element. If so save it & return true.
16662  If not the required element check if buffer or continuation, & if so erase all searchvector
16663  & return false. If OK check if a leading point and if so do up to 2 recursive searches for the 2 exits (trying the 'set' exit first),
16664  checking in each case whether the element fouls an existing diagonal route. If fail on both exits erase searchvector & return false.
16665  If not any of above, store element in SearchVector, increment VectorCount, set the new CurrentTrackElement value from the
16666  SearchElement & the new XLinkPos from SearchElement.XLinkPos, then go back to the while loop for the next step in the search.
16667  When return true have 8 items from CheckCount established, only waiting for EXNumber
16668 */
16669 {
16670  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForNonPreferredRoute," + CurrentTrackElement.LogTrack(14) + "," +
16671  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString() + "," + AnsiString(ReqPosRouteID.GetInt()));
16672  int VectorCount = 0;
16673 
16674 // check for a fouled diagonal for first element. Added for v1.3.2
16675  if((CurrentTrackElement.Link[XLinkPos] == 1) || (CurrentTrackElement.Link[XLinkPos] == 3) || (CurrentTrackElement.Link[XLinkPos] == 7) ||
16676  (CurrentTrackElement.Link[XLinkPos] == 9))
16677  {
16678  if(AllRoutes->DiagonalFouledByRouteOrTrain(8, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc, CurrentTrackElement.Link[XLinkPos]))
16679  {
16680  for(int x = 0; x < VectorCount; x++)
16681  {
16682  SearchVector.erase(SearchVector.end() - 1);
16683  }
16684  Utilities->CallLogPop(2044);
16685  return(false);
16686  }
16687  }
16688  while(true)
16689  {
16690  if(Track->IsLCBarrierFlashingAtHV(2, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc)) // can't set a route through a flashing barrier
16691  {
16692  for(int x = 0; x < VectorCount; x++)
16693  {
16694  SearchVector.erase(SearchVector.end() - 1);
16695  }
16696  Utilities->CallLogPop(1927);
16697  return(false);
16698  }
16699  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
16700  {
16701  for(int x = 0; x < VectorCount; x++)
16702  {
16703  SearchVector.erase(SearchVector.end() - 1);
16704  }
16705  Utilities->CallLogPop(290);
16706  return(false);
16707  }
16708  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
16709  TTrackElement NextTrackElement = Track->TrackElementAt(93, NextPosition);
16710  TPrefDirElement SearchElement(NextTrackElement);
16711  SearchElement.TrackVectorPosition = NextPosition;
16712  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
16713  SearchElement.ELinkPos = NextELinkPos;
16714  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
16715  int NextXLinkPos;
16716  if(SearchElement.ELinkPos == 0)
16717  {
16718  NextXLinkPos = 1;
16719  }
16720  if(SearchElement.ELinkPos == 1)
16721  {
16722  NextXLinkPos = 0;
16723  }
16724  if(SearchElement.ELinkPos == 2)
16725  {
16726  NextXLinkPos = 3;
16727  }
16728  if(SearchElement.ELinkPos == 3)
16729  {
16730  NextXLinkPos = 2;
16731  }
16732  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
16733  {
16734  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
16735  // but may be buffers, continuation or gap
16736  SearchElement.XLinkPos = NextXLinkPos;
16737  }
16738 // Now have SpeedTag, HLoc, VLoc, TrackVectorPosition, ELink, ELinkPos, and for non-points XLink & XLinkPos
16739 // can't set XLink or XLinkPos yet if the element is a leading point.
16740 
16741 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
16742  for(unsigned int x = 0; x < SearchVector.size(); x++)
16743  {
16744  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
16745  {
16746  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
16747  // OK if it's a bridge & routes on different tracks
16748  {
16749  for(int x = 0; x < VectorCount; x++)
16750  {
16751  SearchVector.erase(SearchVector.end() - 1);
16752  }
16753  Utilities->CallLogPop(291);
16754  return(false);
16755  }
16756  }
16757  }
16758 
16759 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
16760  TAllRoutes::TRouteElementPair SecondPair;
16762  Track->TrackElementAt(94, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(95, SearchElement.TrackVectorPosition).VLoc, SecondPair);
16763  if(RoutePair.first > -1)
16764  {
16765  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
16766  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(43, RoutePair.first).GetFixedPrefDirElementAt(64,
16767  RoutePair.second).ELinkPos)))
16768  {
16769  // still OK if start of an expected route
16770  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(4, ReqPosRouteID)) || (RoutePair.second != 0))
16771  {
16772  for(int x = 0; x < VectorCount; x++)
16773  {
16774  SearchVector.erase(SearchVector.end() - 1);
16775  }
16776  Utilities->CallLogPop(292);
16777  return(false); // only allow for start of an expected route
16778  }
16779  }
16780  }
16781  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
16782  {
16783  // OK if it's a bridge & routes on different tracks
16784  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(44, SecondPair.first).GetFixedPrefDirElementAt(65,
16785  SecondPair.second).ELinkPos)))
16786  {
16787  // still OK if start of an expected route
16788  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(5, ReqPosRouteID)) || (SecondPair.second != 0))
16789  {
16790  for(int x = 0; x < VectorCount; x++)
16791  {
16792  SearchVector.erase(SearchVector.end() - 1);
16793  }
16794  Utilities->CallLogPop(293);
16795  return(false); // only allow for start of an expected route
16796  }
16797  }
16798  }
16799 // check if a train on element, unless a bridge & train on different track
16800 // OK of same train as start element - no, drop this
16801 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
16802  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
16803  {
16804  for(int x = 0; x < VectorCount; x++)
16805  {
16806  SearchVector.erase(SearchVector.end() - 1);
16807  }
16808  Utilities->CallLogPop(294);
16809  return(false);
16810  }
16811  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
16812  {
16813  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1))
16814  {
16815  for(int x = 0; x < VectorCount; x++)
16816  {
16817  SearchVector.erase(SearchVector.end() - 1);
16818  }
16819  Utilities->CallLogPop(295);
16820  return(false);
16821  }
16822  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1))
16823  {
16824  for(int x = 0; x < VectorCount; x++)
16825  {
16826  SearchVector.erase(SearchVector.end() - 1);
16827  }
16828  Utilities->CallLogPop(296);
16829  return(false);
16830  }
16831  }
16832 // check for a fouled diagonal (if not leading point - leading point XLink == -1)
16833  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16834  {
16835  if(AllRoutes->DiagonalFouledByRouteOrTrain(3, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16836  {
16837  for(int x = 0; x < VectorCount; x++)
16838  {
16839  SearchVector.erase(SearchVector.end() - 1);
16840  }
16841  Utilities->CallLogPop(297);
16842  return(false);
16843  }
16844  }
16845 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
16846 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
16847 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
16849  {
16850  for(int x = 0; x < VectorCount; x++)
16851  {
16852  SearchVector.erase(SearchVector.end() - 1);
16853  }
16854  Utilities->CallLogPop(1689);
16855  return(false);
16856  }
16857 // check if found it
16858  if(SearchElement.TrackVectorPosition == RequiredPosition)
16859  {
16860  if(SearchElement.TrackType == Points) // can only happen for platform element in CallingOnAllowed function
16861  {
16862  if((SearchElement.ELinkPos == 1) || (SearchElement.ELinkPos == 3))
16863  {
16864  SearchElement.XLinkPos = 0; // select the straight track (for the platform)
16865  }
16866  else
16867  {
16868  SearchElement.XLinkPos = 1;
16869  }
16870 // SearchElement.XLink = SearchElement.Link[XLinkPos]; WRONG!! NajamUddin found this error 17/01/11, XLinkPos is the function input parameter, should be SearchElement.XLinkPos
16871  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos]; // corrected for v0.6a
16872  }
16873  SearchVector.push_back(SearchElement);
16874  VectorCount++; // not really needed but include for tidyness
16875  TotalSearchCount++;
16876  if(!RecursiveCall && SignalHasFailed(3)) //added at v2.13.0
16877  {
16878  for(int x = 0; x < VectorCount; x++)
16879  {
16880  SearchVector.erase(SearchVector.end() - 1);
16881  }
16882  Utilities->CallLogPop(2525);
16883  return(false);
16884  }
16885  Utilities->CallLogPop(298);
16886  return(true);
16887  }
16888 // Not the required element - check if a buffer or continuation
16889  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
16890  {
16891  for(int x = 0; x < VectorCount; x++)
16892  {
16893  SearchVector.erase(SearchVector.end() - 1);
16894  }
16895  Utilities->CallLogPop(299);
16896  return(false);
16897  }
16898 // check if SearchVector exceeds a size of 150
16899  if(SearchVector.size() > 150)
16900  {
16901  for(int x = 0; x < VectorCount; x++)
16902  {
16903  SearchVector.erase(SearchVector.end() - 1);
16904  }
16905  Utilities->CallLogPop(1421);
16906  return(false);
16907  }
16908 //deal with failed points, added at v2.13.0
16909  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && Track->TrackElementAt(1524, SearchElement.TrackVectorPosition).Failed) //leading entry
16910  {
16911  if(Track->TrackElementAt(1525, SearchElement.TrackVectorPosition).Attribute == 0)
16912  {
16913  SearchElement.XLinkPos = 1;
16914  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
16915  }
16916  else
16917  {
16918  SearchElement.XLinkPos = 3;
16919  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
16920  }
16921  }
16922  else if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Trail) && Track->TrackElementAt(1526, SearchElement.TrackVectorPosition).Failed) //trailing entry
16923  {
16924  if((Track->TrackElementAt(1527, SearchElement.TrackVectorPosition).Attribute == 0) && (SearchElement.ELinkPos == 3)) //can't go any further
16925  {
16926  for(int x = 0; x < VectorCount; x++)
16927  {
16928  SearchVector.erase(SearchVector.end() - 1);
16929  }
16930  Utilities->CallLogPop(2533);
16931  return(false);
16932  }
16933  if((Track->TrackElementAt(1528, SearchElement.TrackVectorPosition).Attribute == 1) && (SearchElement.ELinkPos == 1)) //can't go any further
16934  {
16935  for(int x = 0; x < VectorCount; x++)
16936  {
16937  SearchVector.erase(SearchVector.end() - 1);
16938  }
16939  Utilities->CallLogPop(2534);
16940  return(false);
16941  }
16942  }
16943 
16944 // check if reached a non-failed leading point
16945  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && !SearchElement.Failed)
16946  { //added !Failed condition at v2.13.0 to exclude failed points
16947 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
16948  int SearchPos1 = SearchElement.Attribute + 1;
16949  int SearchPos2;
16950  if(SearchPos1 == 2)
16951  {
16952  SearchPos1++;
16953  }
16954  if(SearchPos1 == 1)
16955  {
16956  SearchPos2 = 3;
16957  }
16958  else
16959  {
16960  SearchPos2 = 1;
16961  }
16962 // push element with XLink set to position [SearchPos1]
16963  SearchElement.XLink = SearchElement.Link[SearchPos1];
16964  SearchElement.XLinkPos = SearchPos1;
16965 // check for a fouled diagonal for leading point for XLinkPos == SearchPos1)
16966  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16967  {
16968  if(AllRoutes->DiagonalFouledByRouteOrTrain(4, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16969  {
16970  for(int x = 0; x < VectorCount; x++)
16971  {
16972  SearchVector.erase(SearchVector.end() - 1);
16973  }
16974  Utilities->CallLogPop(300);
16975  return(false);
16976  }
16977  }
16978  SearchVector.push_back(SearchElement);
16979  VectorCount++;
16980  TotalSearchCount++;
16981 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
16982 // Note that NextTrackElement is the TTrackElement that the TPrefDirElement SearchElement is constructed from. Can't use SearchElement in the
16983 // recursive search as has to be a TTrackElement for non-preferred route searches
16984  if(SearchForNonPreferredRoute(6, NextTrackElement, SearchPos1, RequiredPosition, ReqPosRouteID, true))
16985  {
16986  if(!RecursiveCall && SignalHasFailed(4)) //added at v2.13.0
16987  {
16988  for(int x = 0; x < VectorCount; x++)
16989  {
16990  SearchVector.erase(SearchVector.end() - 1);
16991  }
16992  Utilities->CallLogPop(2526);
16993  return(false);
16994  }
16995  Utilities->CallLogPop(301);
16996  return(true);
16997  }
16998  else
16999  {
17000 // remove leading point with XLinkPos [SearchPos1]
17001  SearchVector.erase(SearchVector.end() - 1);
17002  VectorCount--;
17003 // push element with XLink set to position [SearchPos2]
17004  SearchElement.XLink = SearchElement.Link[SearchPos2];
17005  SearchElement.XLinkPos = SearchPos2;
17006 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
17007  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
17008  {
17009  if(AllRoutes->DiagonalFouledByRouteOrTrain(5, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
17010  {
17011  for(int x = 0; x < VectorCount; x++)
17012  {
17013  SearchVector.erase(SearchVector.end() - 1);
17014  }
17015  Utilities->CallLogPop(302);
17016  return(false);
17017  }
17018  }
17019  SearchVector.push_back(SearchElement);
17020  VectorCount++;
17021  TotalSearchCount++;
17022 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
17023  if(SearchForNonPreferredRoute(7, NextTrackElement, SearchPos2, RequiredPosition, ReqPosRouteID, true))
17024  {
17025  if(!RecursiveCall && SignalHasFailed(5)) //added at v2.13.0
17026  {
17027  for(int x = 0; x < VectorCount; x++)
17028  {
17029  SearchVector.erase(SearchVector.end() - 1);
17030  }
17031  Utilities->CallLogPop(2527);
17032  return(false);
17033  }
17034  Utilities->CallLogPop(303);
17035  return(true);
17036  }
17037  else
17038  {
17039  for(int x = 0; x < VectorCount; x++)
17040  {
17041  SearchVector.erase(SearchVector.end() - 1);
17042  }
17043  Utilities->CallLogPop(304);
17044  return(false);
17045  }
17046  }
17047  } // if leading point
17048 
17049 // here if ordinary element, push it, inc VectorCount & update CurrentTrackElement
17050 // ready for next element on route
17051  SearchVector.push_back(SearchElement);
17052  VectorCount++;
17053  TotalSearchCount++;
17054  CurrentTrackElement = SearchElement;
17055  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
17056  } // while(true)
17057 }
17058 
17059 // ---------------------------------------------------------------------------
17060 
17062 
17063 /*
17064  This function is developed from ConvertPrefDirSearchVector, to deal with search elements not
17065  having all values set (since not necessarily on PrefDirs).
17066  Enter with SearchVector established, return if empty. The first element may not have its ELink & XLink etc set
17067  (if it was the start), so these are checked first and set if necessary. All elements now have
17068  all but EXNumber set, so the CheckCount is set to 8 to cover all but EXNumber, and that is then set
17069  for all elements (unless validity check fails) and CheckCount incremented. Finally SetRouteSearchVectorGraphics() is called
17070  to set the route colour and direction graphics.
17071 */
17072 
17073 {
17074  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRemainingSearchVectorValues");
17075  if(SearchVector.size() == 0)
17076  {
17077  throw Exception("Error, SearchVector empty");
17078  }
17079 // first SearchElement may have ELink & XLink not set if entered in GetStart.... i.e if it wasn't already in a route
17080 // hence need to examine and update it if necessary
17081  TPrefDirElement SecondElement;
17082 
17083  if(SearchVector.size() > 1) // if search vector only a single element then first element must have been in a route, and in this case
17084  // all data members will have been set in SearchForNonPreferredRoute except for EXNumber.
17085  // need above check or SecondElement will fail
17086  {
17087  SecondElement = SearchVector.at(1);
17088  // SearchVector.at(0) ELink & XLink not set if was first element in route; XLink also not set if was a leading point though can't be for a route
17089  for(int x = 0; x < 4; x++)
17090  {
17091  if(SearchVector.at(0).Conn[x] == SecondElement.TrackVectorPosition)
17092  {
17093  if(SearchVector.at(0).XLink == -1) // i.e. not set
17094  {
17095  SearchVector.at(0).XLink = SearchVector.at(0).Link[x];
17096  SearchVector.at(0).XLinkPos = x;
17097  }
17098  int ELinkPos;
17099  if(SearchVector.at(0).XLinkPos == 0)
17100  {
17101  ELinkPos = 1; // use actual value rather than 'x' as may be a gap with both ends
17102  }
17103  // linked to 1st searchvector element, & if XLink was set then x may not correspond
17104  if(SearchVector.at(0).XLinkPos == 1)
17105  {
17106  ELinkPos = 0;
17107  }
17108  if(SearchVector.at(0).XLinkPos == 2)
17109  {
17110  ELinkPos = 3;
17111  }
17112  if(SearchVector.at(0).XLinkPos == 3)
17113  {
17114  ELinkPos = 2;
17115  }
17116  if(SearchVector.at(0).ELink == -1) // because was start element, & can't be points, but could be a gap
17117  {
17118  SearchVector.at(0).ELink = SearchVector.at(0).Link[ELinkPos];
17119  SearchVector.at(0).ELinkPos = ELinkPos;
17120  }
17121  break; // no point going any further
17122  }
17123  }
17124  }
17125  for(unsigned int x = 0; x < SearchVector.size(); x++)
17126  {
17127  SearchVector.at(x).CheckCount = 8; // to account for all but EXNumber
17128 // set EXNumber
17129  if(!(SearchVector.at(x).EntryExitNumber()))
17130  {
17131  throw Exception("Error in EntryExitNumber 3");
17132  }
17133  SearchVector.at(x).CheckCount++;
17134 // all values now incorporated
17135  }
17136 
17137  SetRouteSearchVectorGraphics(5, false, false); // change graphic colour to the route colour
17138 // This function is only called here for nonsignals routes, so AutoSigsFlag & PrefDirRoute both false
17139 // PrefDir is validated in ConvertAndAddNonPreferredRouteSearchVector
17140  Utilities->CallLogPop(305);
17141 }
17142 
17143 // ---------------------------------------------------------------------------
17144 
17146 
17147 /*
17148  This function is very similar to ConvertAndAddPreferredRouteSearchVector except that the route in SearchVector can't be an
17149  AutoSigsRoute.
17150  Action varies depending on whether it is a completely new route, or an extension of an existing route at the
17151  beginning or the end.
17152  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
17153  Check if route end selection is in an existing route (ReqPosRouteID > -1), if so and existing route is non-autosigs
17154  add its elements to the SearchVector then delete the route, decrementing StartSelectionRouteNumber if the RequPosRouteNumber was
17155  less than StartSelectionRouteID. If existing route is AutoSigs then the final search element is dropped from the SearchVector,
17156  since the new route will end adjacent to the AutoSigs route, and the existing route is left as it is.
17157  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
17158  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
17159 
17160  Check if StartSelectionRouteID set (extending an existing route) and if so and if existing route non-autosig, then add the new route
17161  to the existing route (start element not stored in searchvector), call SetRoutePoints & SetRouteSignals for the extended route and return.
17162  If the existing route is autosig, then leave the existing route as it is and continue as for routes that aren't linked to an existing
17163  route at the start.
17164 
17165  Check the validity of the route in SearchVector, and create a new route using StoreOneRoute. Finally call SetRoutePoints & SetRouteSignals
17166  for the new route and return.
17167 */
17168 
17169 {
17170  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddNonPreferredRouteSearchVector," +
17171  AnsiString(ReqPosRouteID.GetInt()));
17172  if(SearchVector.size() < 1)
17173  {
17174  Utilities->CallLogPop(306);
17175  return;
17176  }
17177  PrefDirVector = SearchVector; // this copy is to validate the vector up to this point,
17178  if(!ValidatePrefDir(6))
17179  {
17180  Utilities->CallLogPop(307);
17181  return;
17182  }
17183  TAllRoutes::TLockedRouteClass LockedRouteObject;
17184 
17186  unsigned int TruncatePrefDirPosition = 0;
17187 
17188  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartSelectionRouteID as would have failed in GetNextRouteElement
17189 /* if have ReqPosRouteID:
17190  if existing route non-autosig, then add the old route to the SearchVector then delete the old route
17191  if existing route autosig, drop the final search element in the new route, leave the existing route as it is,
17192  then enter the new route into the AllRoutesVector
17193 */
17194  {
17196  {
17197  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(46, ReqPosRouteID).PrefDirSize();
17198  x++) // start at 1 as first element already in SearchVector
17199  {
17201  }
17202  // note that route numbers in map adjusted when ReqPos route cleared
17204  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
17205  // set during ClearRouteDuringRouteBuildingAt)
17207  {
17210  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
17211  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
17212  }
17213  }
17215  {
17216  SearchVector.pop_back();
17217  }
17218  }
17219  if(StartSelectionRouteID > -1)
17220 /* if have StartSelectionRouteID:
17221  if existing route non-autosig, then add the new route to the existing route (start element not stored in searchvector)
17222  if existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
17223 */
17224  {
17226  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
17227  {
17229  {
17230  int RouteNumber = AllRoutes->GetRouteVectorNumber(1, StartSelectionRouteID);
17231  for(unsigned int x = 0; x < SearchVector.size(); x++)
17232  {
17234  RouteNumber, GetFixedSearchElementAt(7, x));
17235  // find & store locked route truncate position in PrefDirVector for later use
17237  {
17238  if(GetFixedSearchElementAt(16, x).TrackVectorPosition == int(AllRoutes->LockedRouteTruncateTrackVectorPosition))
17239  {
17240  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(176, RouteNumber).PrefDirSize() - 1;
17241  }
17242  }
17243  }
17245  {
17246  throw Exception("Failed to validate extended route for nonpreferred route");
17247  }
17250  AllRoutes->GetModifiableRouteAtIDNumber(9, StartSelectionRouteID).SetLCChangeValues(2, false); // PrefDirRoute is false
17251  // now add the reinstated locked route if required and set signals accordingly
17252  // shouldn't ever need to access this as the train that has caused the locked route will be ahead of the route to be added,
17253  // and it will have removed the route elements that it is standing on, but include in case there's some obscure condition
17254  // that I haven't thought of
17256  {
17257  LockedRouteObject.RouteNumber = RouteNumber;
17258  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
17259  // now reset the signals for the locked route
17260  AllRoutes->SetAllRearwardsSignals(12, 0, RouteNumber, TruncatePrefDirPosition);
17261  for(int c = AllRoutes->GetFixedRouteAt(177, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
17262  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
17263  {
17264  // return all signals to red in route section to be truncated
17265  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(178, RouteNumber).PrefDirVector.at(c);
17266  TTrackElement & TrackElement = Track->TrackElementAt(813, PrefDirElement.TrackVectorPosition);
17267  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
17268  {
17269  TrackElement.Attribute = 0;
17270  Track->PlotSignal(11, TrackElement, Display);
17271  Display->PlotOutput(115, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
17272  Display->PlotOutput(116, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
17273  }
17274  }
17275  }
17276  AllRoutes->CheckMapAndRoutes(3); // test
17277  Utilities->CallLogPop(308);
17278  return;
17279  }
17280  }
17281  else
17282  {
17284  }
17285 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
17286 // hence nothing to do here
17287  }
17288  PrefDirVector = SearchVector; // copy again prior to storing as a route as SearchVector may have been extended
17289  if(!ValidatePrefDir(8)) // validate PrefDir for all new route elements
17290  {
17291  throw Exception("Failed to validate single route for nonpreferred route");
17292  }
17293  AllRoutes->StoreOneRoute(2, this);
17294  AllRoutes->GetModifiableRouteAt(6, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(3); // new addition
17295  AllRoutes->GetModifiableRouteAt(17, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(7); // new addition
17296  AllRoutes->GetModifiableRouteAt(19, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(3, false); // ConsecSignalsRoute is false
17297  AllRoutes->CheckMapAndRoutes(4); // test
17298  Utilities->CallLogPop(309);
17299 }
17300 
17301 // ---------------------------------------------------------------------------
17302 
17303 void TOneRoute::SetRoutePoints(int Caller) const
17304 /*
17305  Examine each set of points in the route to see if entry or exit is via the straight or diverging trailing
17306  link, and set the attribute accordingly (don't need to worry about linked routes, points in those will have been set
17307  when they were created.
17308 */
17309 {
17310  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRoutePoints");
17311  if(!PrefDirVector.empty())
17312  {
17313  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
17314  {
17315  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 1) || (PrefDirPtr->XLinkPos == 1))) //1=straight trailing
17316  {
17317  Track->TrackElementAt(96, PrefDirPtr->TrackVectorPosition).Attribute = 0; // 0=straight
17318  Track->PlotPoints(3, Track->TrackElementAt(97, PrefDirPtr->TrackVectorPosition), Display, false);
17319  }
17320  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 3) || (PrefDirPtr->XLinkPos == 3))) //3=diverging trailing
17321  {
17322  Track->TrackElementAt(98, PrefDirPtr->TrackVectorPosition).Attribute = 1; // 1=diverging
17323  Track->PlotPoints(4, Track->TrackElementAt(99, PrefDirPtr->TrackVectorPosition), Display, false);
17324  }
17325  }
17326  }
17327  Utilities->CallLogPop(327);
17328 }
17329 
17330 // ---------------------------------------------------------------------------
17331 
17332 void TOneRoute::SetRouteSignals(int Caller) const
17333 /* Used for new train additions in AddTrain and in route setting
17334  Set the signals as follows:-
17335  First check whether there is a linked forward route, and if so use FindForwardTargetSignalAttribute to work along it from the start
17336  until find a train (return Attribute = 0 & NextForwardLinkedRouteNumber = -1), a buffer (return Attribute = 1 &
17337  NextForwardLinkedRouteNumber = -1), a continuation (return Attribute = 3 & NextForwardLinkedRouteNumber = -1) or a forward-facing
17338  signal. If find a signal its attribute value + 1 up to a maximum value of 3 is returned & NextForwardLinkedRouteNumber = -1.
17339  The above Attribute values represent the 'target' attribute, from which all rearwards signals in turn in the new route are set,
17340  the first using the returned attribute value and subsequent ones incrementing the Attribute up to a maximum of 3. All the foregoing
17341  return true, as does finding none of the above and no onward linked forward route (NextForwardLinkedRouteNumber = -1). If none
17342  of the foregoing are found but there is a further forward linked forward route then the function returns false with
17343  NextForwardLinkedRouteNumber = the next forward linked route number, to allow that to be examined similarly, and Attribute = 0.
17344 
17345  When the target Attribute is found (will be 0 if no forward linked route), then SetAllRearwardsSignals is used to work back from
17346  the end of the route setting each forward-facing signal one step nearer green as described above, until either reach the end of all
17347  linked rearwards routes or find a train. If find a train in the current route then signals behind it (and behind any other trains
17348  in the current route) are set appropriately (including in linked rear routes), but if find a train in a linked rear route then no
17349  further signals are set. If there is no forward linked route and the front end of the current route is a buffer then
17350  SetAllRearwardsSignals (in its call to SetRearwardsSignalsReturnFalseForTrain) treats it as a red signal, and if a continuation,
17351  as a green signal.
17352 */
17353 {
17354  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSignals");
17355  if(!PrefDirVector.empty())
17356  {
17357  // get target Attribute value, check first if there is a forward linked route
17358  TPrefDirElement LastElement = GetFixedPrefDirElementAt(185, PrefDirSize() - 1);
17359  TPrefDirElement FirstElement = GetFixedPrefDirElementAt(186, 0);
17360  int ForwardLinkedRouteNumber, Attribute = 0;
17361  if(LastElement.Conn[LastElement.XLinkPos] > -1)
17362  // Note that LastElement can't be points but can be linked to points
17363  {
17364  if(AllRoutes->GetRouteTypeAndNumber(16, LastElement.Conn[LastElement.XLinkPos], LastElement.ConnLinkPos[LastElement.XLinkPos],
17365  ForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
17366  {
17367  if(ForwardLinkedRouteNumber > -1)
17368  {
17369  int NextForwardLinkedRouteNumber = -1;
17370  while(!(AllRoutes->GetFixedRouteAt(171, ForwardLinkedRouteNumber).FindForwardTargetSignalAttribute(1, NextForwardLinkedRouteNumber,
17371  Attribute)))
17372  {
17373  ForwardLinkedRouteNumber = NextForwardLinkedRouteNumber;
17374  }
17375  // if find a train before a signal then Attribute = 0, else if find end of route is a buffer then Attribute = 1, or a continuation then
17376  // Attribute = 3, else if find signal then Attribute = (signal attribute + 1) up to a max value of 3. All these return true, if find a
17377  // forward linked route then the routenumber is set in NextForwardLinkedRouteNumber, Attribute = 0 & returns false.
17378  }
17379  }
17380  }
17381  int RouteNumber;
17382  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(15, GetFixedPrefDirElementAt(187, 0).TrackVectorPosition,
17383  GetFixedPrefDirElementAt(193, 0).XLinkPos, RouteNumber);
17384  if(RouteType != TAllRoutes::NoRoute)
17385  // it will be, above only used to get RouteNumber, can choose any element in the route so use GetFixedPrefDirElementAt
17386  {
17387  AllRoutes->SetAllRearwardsSignals(8, Attribute, RouteNumber, PrefDirSize() - 1);
17388  }
17389  }
17390  Utilities->CallLogPop(1720);
17391 }
17392 
17393 // ---------------------------------------------------------------------------
17394 
17395 bool TOneRoute::PointsToBeChanged(int Caller, int &NewFailedPointsTVPos) const
17396 {
17397  //true if at any point in SearchVector points have to be changed,
17398  //changed to give every point to be changed in route to have a chance of failure, but if one fails then don't look any further
17399  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PointsToBeChanged");
17400  NewFailedPointsTVPos = -1; //default value for no new failure
17401  bool PointsChanged = false;
17402  if(!SearchVector.empty())
17403  {
17404  for(TPrefDirVectorConstIterator SearchPtr = SearchVector.begin(); SearchPtr != SearchVector.end(); SearchPtr++)
17405  {
17406  TTrackElement &TE = Track->TrackElementAt(1504, SearchPtr->TrackVectorPosition);
17407  //check for an existing failed point where needs to change to make the route
17408  int Attr = TE.Attribute;
17409  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 1) || (SearchPtr->XLinkPos == 1))) // 1=want to go straight
17410  {
17411  if(Attr == 1) //currently set to diverge
17412  {
17413  //here add new failure possibility at v2.13.0
17414  if(Utilities->DelayMode != Nil)
17415  {
17416  if((random(Utilities->PointChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice, but if failed should already have been picked up during search
17417  {
17419  NewFailedPointsTVPos = SearchPtr->TrackVectorPosition;
17420  IFE.TVPos = NewFailedPointsTVPos;
17421  TE.Failed = true;
17422  TE.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = TE.SpeedLimit01; //store these values temporarily, points aren't bridges so can use these
17424  TE.SpeedLimit01 = 10; //values while failed
17425  TE.SpeedLimit23 = 10;
17426  Display->WarningLog(13, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points failed at " + TE.ElementID);
17427  PerfLogForm->PerformanceLog(36, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Points failed at " + TE.ElementID);
17428  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
17429  //set repair time, random value in minutes between 10 and 179
17430  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime); //between 10 and 179 minutes at random
17431  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
17432  IFE.RepairTime = RepairTime;
17434  Track->FailedPointsVector.push_back(IFE);
17435  Utilities->CallLogPop(1717);
17436  return(true); //return so only allow one failure per route
17437  }
17438  }
17439  PointsChanged = true; //this is used for setting the flash time
17440  }
17441  }
17442  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 3) || (SearchPtr->XLinkPos == 3))) // 3=want to diverge
17443  {
17444  if(Attr == 0) //currently set to go straight
17445  {
17446  //here add failure possibility at v2.13.0
17447  if(Utilities->DelayMode != Nil)
17448  {
17449  if((random(Utilities->PointChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice, but if failed should already have been picked up during search
17450  {
17452  NewFailedPointsTVPos = SearchPtr->TrackVectorPosition;
17453  IFE.TVPos = NewFailedPointsTVPos;
17454  TE.Failed= true;
17455  TE.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = TE.SpeedLimit01; //store these values temporarily, points aren't bridges so can use these
17457  TE.SpeedLimit01 = 10; //values while failed
17458  TE.SpeedLimit23 = 10;
17459  Display->WarningLog(14, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points failed at " + TE.ElementID);
17460  PerfLogForm->PerformanceLog(37, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Points failed at " + TE.ElementID);
17461  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
17462  //set repair time, random value in minutes between 10 and 179
17463  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime);
17464  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
17465  IFE.RepairTime = RepairTime;
17467  Track->FailedPointsVector.push_back(IFE);
17468  Utilities->CallLogPop(1718);
17469  return(true); //only allow one failure per route
17470  }
17471  }
17472  PointsChanged = true;
17473  }
17474  }
17475  }
17476  }
17477  Utilities->CallLogPop(1719);
17478  return(PointsChanged);
17479 }
17480 
17481 // ---------------------------------------------------------------------------
17482 
17483 bool TOneRoute::FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
17484 /*
17485  Works forward through the route until finds:-
17486  (a) a train - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
17487  (b) end of route at buffers - Attribute = 1, NextForwardLinkedRouteNumber = -1 & returns true;
17488  (c) end of route at continuation - Attribute = 3, NextForwardLinkedRouteNumber = -1 & returns true;
17489  (d) level crossing with barriers not down - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
17490  (e) forward-facing signal - Attribute = 1 + signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true;
17491  (f) end of route not at any of foregoing and with no linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = -1 &
17492  returns true;
17493  (g) linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = the routenumber of the forward route & returns false.
17494 */
17495 {
17496  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindForwardTargetSignalAttribute");
17497  Attribute = 0;
17498  NextForwardLinkedRouteNumber = -1;
17499  for(unsigned int x = 0; x < PrefDirSize(); x++)
17500  {
17501  int TrainID = Track->TrackElementAt(100, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnElement;
17502  if(PrefDirVector.at(x).TrackType == Bridge)
17503  {
17504  if(PrefDirVector.at(x).XLinkPos < 2)
17505  {
17506  TrainID = Track->TrackElementAt(101, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
17507  }
17508  else
17509  {
17510  TrainID = Track->TrackElementAt(102, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
17511  }
17512  }
17513  if(TrainID != -1)
17514  {
17515  Utilities->CallLogPop(328);
17516  return(true);
17517  }
17518  if(PrefDirVector.at(x).TrackType == Buffers)
17519  {
17520  Attribute = 1;
17521  Utilities->CallLogPop(329);
17522  return(true);
17523  }
17524  if(PrefDirVector.at(x).TrackType == Continuation)
17525  {
17526  Attribute = 3;
17527  Utilities->CallLogPop(330);
17528  return(true);
17529  }
17530  if(Track->IsLCAtHV(42, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
17531  {
17532  if(!Track->IsLCBarrierDownAtHV(3, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
17533  {
17534  Attribute = 0;
17535  Utilities->CallLogPop(1950);
17536  return(true);
17537  }
17538  }
17539  if(PrefDirVector.at(x).Config[PrefDirVector.at(x).XLinkPos] == Signal)
17540  {
17541  Attribute = Track->TrackElementAt(103, PrefDirVector.at(x).TrackVectorPosition).Attribute + 1;
17542  if(Attribute > 3)
17543  {
17544  Attribute = 3;
17545  }
17546  Utilities->CallLogPop(331);
17547  return(true);
17548  }
17549  if(x == PrefDirSize() - 1)
17550  {
17551  TPrefDirElement LastElement = PrefDirVector.at(x);
17552  if(LastElement.Conn[LastElement.XLinkPos] > -1)
17553  {
17554  if(AllRoutes->GetRouteTypeAndNumber(2, LastElement.Conn[LastElement.XLinkPos],
17555  Track->GetNonPointsOppositeLinkPos(LastElement.ConnLinkPos[LastElement.XLinkPos]), NextForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
17556  {
17557  Attribute = 0;
17558  Utilities->CallLogPop(332);
17559  return(false);
17560  }
17561  }
17562  }
17563  }
17564  Utilities->CallLogPop(333);
17565  return(true);
17566 }
17567 
17568 // ---------------------------------------------------------------------------
17569 
17570 bool TOneRoute::SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
17571 /*
17572  This function is only called by TAllRoutes::SetAllRearwardsSignals.
17573 
17574  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
17575  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
17576  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
17577  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
17578  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
17579  a route.
17580 
17581  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
17582  signal. If find a signal set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
17583  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3 [addition at v2.9.2: if signal or element beyond
17584  it is in a locked route then set signal to red & change Attribute to 0 - this fault reported by Simon Banham 21/07/21 as an image]. and continue working
17585  backwards for the next signal (or train - return false as before) and so on. On completion Attribute is passed back from the function as a
17586  reference. If no train is found before the beginning of the route is reached the function returns true
17587 
17588  In setting signals skip the first position if it's a signal and if truncating - otherwise the truncated signal counts as the first red
17589  and the next rearwards signal becomes yellow, although it's the first in the route
17590 */
17591 {
17592  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRearwardsSignalsReturnFalseForTrain," + AnsiString(Attribute) + "," +
17593  AnsiString(PrefDirVectorStartPosition));
17594  Graphics::TBitmap *EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default values
17595  Graphics::TBitmap *EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd;
17596 // if no train between end of route and PrefDirVectorStartPosition, route not in ContinuationAutoSigVector
17597 // & not truncating a route, then Attribute can be modified if end is buffers or continuation
17598  bool SkipContinuationAndBufferAttributeChange = false;
17599 
17600  if(!PrefDirVector.empty())
17601  {
17602  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr < PrefDirVector.end(); PrefDirPtr++)
17603  {
17604  int TrainID = Track->TrackElementAt(104, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
17605  if(PrefDirPtr->TrackType == Bridge)
17606  {
17607  if(PrefDirPtr->XLinkPos < 2)
17608  {
17609  TrainID = Track->TrackElementAt(105, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
17610  }
17611  else
17612  {
17613  TrainID = Track->TrackElementAt(106, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
17614  }
17615  }
17616  if(TrainID != -1)
17617  {
17618  SkipContinuationAndBufferAttributeChange = true;
17619  break;
17620  }
17621  }
17622 
17625  {
17626  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.begin(); AutoSigVectorIT < TrainController->ContinuationAutoSigVector.end();
17627  AutoSigVectorIT++)
17628  {
17629  if(!AllRoutes->AllRoutesVector.empty())
17630  {
17631  if((&AllRoutes->AllRoutesVector.front() + AutoSigVectorIT->RouteNumber) == this)
17632  {
17633  SkipContinuationAndBufferAttributeChange = true;
17634  break;
17635  }
17636  }
17637  }
17638  }
17640  {
17641  SkipContinuationAndBufferAttributeChange = true;
17642  }
17643  if(!SkipContinuationAndBufferAttributeChange)
17644  {
17645  if(PrefDirVector.back().TrackType == Buffers)
17646  {
17647  Attribute = 1; // treat buffer as red signal
17648  }
17649  if(PrefDirVector.back().TrackType == Continuation)
17650  {
17651  Attribute = 3; // treat continuation as a green signal
17652  }
17653  }
17654  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
17655  {
17656  int TrainID = Track->TrackElementAt(107, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
17657  if(PrefDirPtr->TrackType == Bridge)
17658  {
17659  if(PrefDirPtr->XLinkPos < 2)
17660  {
17661  TrainID = Track->TrackElementAt(108, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
17662  }
17663  else
17664  {
17665  TrainID = Track->TrackElementAt(109, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
17666  }
17667  }
17668  if(TrainID != -1)
17669  {
17670  Utilities->CallLogPop(334);
17671  return(false);
17672  }
17673  // if find an LC that is closed to trains (or flashing - may be extending an earlier route with flashing LCs) then reset
17674  // the attribute to 0 so first signal behind the LC is red
17675  if(Track->IsLCAtHV(20, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
17676  {
17677  if(!Track->IsLCBarrierDownAtHV(1, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
17678  {
17679  Attribute = 0;
17680  }
17681  }
17682 // now set signals, but skip the first position if it's a signal on an unrestricted route and truncating - otherwise the truncated signal
17683 // counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
17684  if(PrefDirPtr->Config[PrefDirPtr->XLinkPos] == Signal)
17685  {
17686  if((!AllRoutes->RouteTruncateFlag) || (PrefDirPtr != (PrefDirVector.begin() + PrefDirVectorStartPosition)) || PrefDirPtr->AutoSignals ||
17687  PrefDirPtr->PrefDirRoute)
17688  {
17689 //new section at v2.9.2 to check for pref dir element in a locked route, and if so set Attribute to 0 (red). When emerge from locked route Attribute
17690 //still 0 so first signal behind it also stays red. After that Attribute goes back to normal.
17691  int LockedVecNum = 0; //not used
17692  TPrefDirElement DummyPrefDir; //not used
17693  bool KeepAttributeAt0ForLockedRoute = false;
17694  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(15, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, DummyPrefDir,
17695  LockedVecNum))
17696  {
17697  Attribute = 0;
17698  KeepAttributeAt0ForLockedRoute = true;
17699  }
17700 //end of v2.9.2 addition
17701 
17702  if(Track->TrackElementAt(1529, PrefDirPtr->TrackVectorPosition).Failed) //addition at v2.13.0 for signal failures
17703  {
17704  Attribute = 0; //stays at 0
17705  }
17706 
17707  if(Attribute < 3)
17708  {
17709  Track->TrackElementAt(110, PrefDirPtr->TrackVectorPosition).Attribute = Attribute;
17710  }
17711  else
17712  {
17713  Track->TrackElementAt(111, PrefDirPtr->TrackVectorPosition).Attribute = 3; // green
17714  }
17715  Track->PlotSignal(1, Track->TrackElementAt(112, PrefDirPtr->TrackVectorPosition), Display);
17716  if(AllRoutes->GetRouteTypeAndGraphics(1, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, EXGraphicPtr,
17717  EntryDirectionGraphicPtr) != TAllRoutes::NoRoute)
17718  {
17719  Display->PlotOutput(16, Track->TrackElementAt(113, PrefDirPtr->TrackVectorPosition).HLoc * 16,
17720  Track->TrackElementAt(114, PrefDirPtr->TrackVectorPosition).VLoc * 16, EXGraphicPtr);
17721  Display->PlotOutput(17, Track->TrackElementAt(115, PrefDirPtr->TrackVectorPosition).HLoc * 16,
17722  Track->TrackElementAt(116, PrefDirPtr->TrackVectorPosition).VLoc * 16, EntryDirectionGraphicPtr);
17723  }
17724  if((Attribute < 3) && !KeepAttributeAt0ForLockedRoute)
17725  {
17726  Attribute++;
17727  }
17728  Display->Update(); // update after recent plots
17729  }
17730  }
17731  }
17732  }
17733  Utilities->CallLogPop(335);
17734  return(true);
17735 }
17736 
17737 // ---------------------------------------------------------------------------
17738 
17739 void TOneRoute::GetRouteTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
17740 /*
17741  Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFlag value of NotInRoute.
17742  If it is in a route but the element selected is invalid, then a message is given and returns with a ReturnFlag value of
17743  InRouteFalse. Otherwise the route is truncated at and including the element that matches H & V with a ReturnFlag value of InRouteTrue.
17744  Selection invalid if select a bridge; trying to leave a single element; last element to be left
17745  not a signal (for PrefDirRoute or has AutoSigsFlag set); last element to be left a bridge, points or crossover (for not
17746  PrefDirRoute & AutoSigsFlag not set), or part of route locked. Check if a train approaching or occupying route and lock route
17747  if required after offering the user the choice to continue or not. Then SetAllRearwardsSignals is called to set signals before the
17748  truncate point, beginning with a red signal, and RemoveRouteElement called for all elements from the end to and including the truncate point.
17749 */
17750 {
17751  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
17752  "," + AnsiString((short)PrefDirRoute));
17753  bool ElementInRoute = false;
17754  bool TrainOccupyingRoute = false;
17755 
17756  for(unsigned int b = 0; b < PrefDirSize(); b++)
17757  {
17758  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
17759  {
17760  ElementInRoute = true;
17761  break;
17762  }
17763  }
17764  if(!ElementInRoute)
17765  {
17766  ReturnFlag = NotInRoute;
17767  Utilities->CallLogPop(336);
17768  return;
17769  }
17770 // it is in the route so continue, first look for a train or a flashing level crossing
17771  for(int b = PrefDirSize() - 1; b >= 0; b--)
17772  {
17773  int TrainID = Track->TrackElementAt(117, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
17774  if(PrefDirVector.at(b).TrackType == Bridge)
17775  {
17776  if(PrefDirVector.at(b).XLinkPos < 2)
17777  {
17778  TrainID = Track->TrackElementAt(118, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
17779  }
17780  else
17781  {
17782  TrainID = Track->TrackElementAt(119, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
17783  }
17784  }
17785  if(TrainID != -1)
17786  {
17787 // TrainController->StopTTClockMessage(56, "Can't truncate a route that is occupied by a train");
17788 // ReturnFlag = InRouteFalse;
17789 // Utilities->CallLogPop(337);
17790 // return;
17791 // above removed at v2.1.0 so that routes can be locked when occupied, below added
17792  TrainOccupyingRoute = true; // train is forward of the truncate point
17793  }
17794  if(Track->IsLCBarrierFlashingAtHV(3, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
17795  {
17796  TrainController->StopTTClockMessage(79, "Can't cancel a route containing a level crossing that is changing state");
17797  ReturnFlag = InRouteFalse;
17798  Utilities->CallLogPop(1941);
17799  return;
17800  }
17801  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
17802  {
17803  break; // OK found truncate element & no flashing LC in front
17804  }
17805  }
17806 
17807  for(unsigned int b = 0; b < PrefDirSize(); b++)
17808  {
17809  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc)) // b = the truncate point
17810  {
17811  if(PrefDirVector.at(b).TrackType == Bridge)
17812  {
17813  TrainController->StopTTClockMessage(57, "Can't select a bridge as a route truncate point");
17814  ReturnFlag = InRouteFalse;
17815  Utilities->CallLogPop(338);
17816  return;
17817  }
17818  if(b == 1)
17819  {
17820  TrainController->StopTTClockMessage(58, "Can't truncate to a single route element");
17821  ReturnFlag = InRouteFalse;
17822  Utilities->CallLogPop(339);
17823  return;
17824  }
17825  if(b > 0)
17826  {
17827  TPrefDirElement TempElement = PrefDirVector.at(b - 1);
17828  if(TempElement.PrefDirRoute || TempElement.AutoSignals)
17829  {
17830  if(TempElement.Config[TempElement.XLinkPos] != Signal)
17831  {
17832  TrainController->StopTTClockMessage(59, "Must truncate to a valid signal - select position after signal");
17833  ReturnFlag = InRouteFalse;
17834  Utilities->CallLogPop(340);
17835  return;
17836  }
17837  }
17838  else
17839  {
17840  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
17841  {
17842  TrainController->StopTTClockMessage(60, "Can't truncate to points, bridge or crossover");
17843  ReturnFlag = InRouteFalse;
17844  Utilities->CallLogPop(341);
17845  return;
17846  }
17847  }
17848  }
17849  int RouteNumber;
17851 // Have to call RouteLockingRequired before SetAllRearwardsSignals because RouteLockingRequired tests the first rearward signal, if it is
17852 // red then locking is not required, and if call SetAllRearwardsSignals first then it will set the first rearward signal to red.
17853 
17854 // check if part of this route already locked & disallow if so
17855  if(!(AllRoutes->LockedRouteVector.empty()))
17856  {
17858  {
17859  if(LRVIT->RouteNumber == RouteNumber)
17860  {
17861  TrainController->StopTTClockMessage(61, "Can't truncate a route that is already part-locked");
17862  ReturnFlag = InRouteFalse;
17863  Utilities->CallLogPop(749);
17864  return;
17865  }
17866  }
17867  }
17868  if(AllRoutes->RouteLockingRequired(0, RouteNumber, b) || TrainOccupyingRoute) // added TrainOccupyingRoute at v2.1.0,
17869  // RouteLockingRequired only checks for trains approaching
17870  {
17873  int button = Application->MessageBox(L"Train approaching or occupying route, YES to lock route (2 minutes to release), NO to cancel",
17874  L"Warning!", MB_YESNO | MB_ICONWARNING);
17875  TrainController->BaseTime = TDateTime::CurrentDateTime();
17877  if(button == IDNO)
17878  {
17879  ReturnFlag = InRouteTrue; // still return true even though don't act on it
17880  Utilities->CallLogPop(342);
17881  return;
17882  }
17883  AnsiString LocID = AnsiString(Track->TrackElementAt(534, PrefDirVector.at(b).TrackVectorPosition).ElementID);
17884  TrainController->LogActionError(0, "", "", FailLockedRoute, LocID);
17885  TAllRoutes::TLockedRouteClass LockedRoute;
17886  bool ExistingLockedRouteModified = false;
17887  LockedRoute.RouteNumber = RouteNumber;
17888  LockedRoute.TruncateTrackVectorPosition = PrefDirVector.at(b).TrackVectorPosition;
17889  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
17890  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
17891  LockedRoute.LockStartTime = TrainController->TTClockTime;
17892 // but first check if this route already in LockedRouteVector (i.e. locked further along), and if so just change that vector entry
17893 // to use the new TruncateTrackVectorPosition & LockStartTime
17894  if(!AllRoutes->LockedRouteVector.empty())
17895  {
17896  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.begin(); LRVIT < AllRoutes->LockedRouteVector.end();
17897  LRVIT++)
17898  {
17899  if(LRVIT->RouteNumber == RouteNumber)
17900  {
17901  LRVIT->TruncateTrackVectorPosition = LockedRoute.TruncateTrackVectorPosition;
17902  LRVIT->LockStartTime = LockedRoute.LockStartTime;
17903  ExistingLockedRouteModified = true;
17904  }
17905  }
17906  }
17907  if(!ExistingLockedRouteModified)
17908  {
17909  AllRoutes->LockedRouteVector.push_back(LockedRoute);
17910  }
17911  AllRoutes->SetAllRearwardsSignals(2, 0, RouteNumber, b);
17912  for(int c = PrefDirSize() - 1; c >= (int)b; c--) // must use int for >= test to succeed when b == 0
17913  {
17914  // return all signals to red in route section to be truncated
17915  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(61, RouteNumber).PrefDirVector.at(c);
17916  TTrackElement & TrackElement = Track->TrackElementAt(120, PrefDirElement.TrackVectorPosition);
17917  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
17918  {
17919  TrackElement.Attribute = 0;
17920  Track->PlotSignal(2, TrackElement, Display);
17921  Display->PlotOutput(18, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
17922  Display->PlotOutput(19, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
17923  }
17924  }
17925 // Display->Update();//not needed as Clearand... called on return from GetAllRoutesTruncateElement in InterfaceUnit
17926  ReturnFlag = InRouteTrue;
17927  }
17928  else
17929  {
17930  AllRoutes->SetAllRearwardsSignals(3, 0, RouteNumber, b);
17931  for(int c = PrefDirSize() - 1; c >= (int)b; c--) // must use int for >= test to succeed when b == 0
17932  {
17933  AllRoutes->RemoveRouteElement(5, LastElementPtr(3)->HLoc, LastElementPtr(4)->VLoc, LastElementPtr(5)->ELink);
17934  ReturnFlag = InRouteTrue;
17935  }
17936  }
17937  AllRoutes->CheckMapAndRoutes(5); // test
17938  Utilities->CallLogPop(343);
17939  return;
17940  }
17941  }
17942  ReturnFlag = NotInRoute;
17943  Utilities->CallLogPop(344);
17944 }
17945 
17946 // ---------------------------------------------------------------------------
17948 /*
17949  This is used when a train enters a route set in the opposite direction of travel (or at a crossover on a non-route line when the other
17950  track is in a route). The complete route is cancelled (but not linked routes), and all signals in the route are set to red.
17951  First all signals are set to red and replotted (without any route colours), then SetAllRearwardsSignals is called from the
17952  beginning of the route to set all linked rearwards route signals appropriately. Then all elements are removed from the route
17953  and RebuildRailwayFlag set (examined in Interface unit at each clock tick) to force a ClearandRebuildRailway to get rid of
17954  the route colours.
17955 */
17956 {
17957  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ForceCancelRoute");
17958  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
17960  int RouteNumber;
17961  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(4, GetFixedPrefDirElementAt(86, 0).TrackVectorPosition,
17962  GetFixedPrefDirElementAt(87, 0).XLinkPos, RouteNumber);
17963 
17964  if(RouteType != TAllRoutes::NoRoute) // it won't be, above only used to get RouteNumber for setting rearwards signals
17965  {
17966  for(unsigned int x = 0; x < PrefDirSize(); x++) // set all signals in route to red regardless of direction
17967  {
17968  if(PrefDirVector.at(x).TrackType == SignalPost)
17969  {
17970  Track->TrackElementAt(121, PrefDirVector.at(x).TrackVectorPosition).Attribute = 0; // red
17971  Track->PlotSignal(3, Track->TrackElementAt(122, PrefDirVector.at(x).TrackVectorPosition), Display);
17972  }
17973  }
17974  AllRoutes->SetAllRearwardsSignals(4, 0, RouteNumber, 0);
17975 // already set all signals to red in route so start at start of route for further rearwards signal setting
17976  }
17977  for(int c = PrefDirSize() - 1; c >= 0; c--) // must use int for >= test to succeed when b == 0
17978  {
17979  AllRoutes->RemoveRouteElement(6, LastElementPtr(6)->HLoc, LastElementPtr(7)->VLoc, LastElementPtr(8)->ELink);
17980  }
17981  AllRoutes->RebuildRailwayFlag = true; // set to force a ClearandRebuildRailway at next clock tick if not in zoom-out mode
17982  AllRoutes->CheckMapAndRoutes(9); // test
17983  TrainController->BaseTime = TDateTime::CurrentDateTime();
17985  Utilities->CallLogPop(345);
17986  return;
17987 }
17988 
17989 // ---------------------------------------------------------------------------
17990 
17991 void TOneRoute::SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
17992 /*
17993  Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector.
17994 */
17995 {
17996  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSearchVectorGraphics," + AnsiString((short)AutoSigsFlag) + "," +
17997  AnsiString((short)PrefDirRoute));
17998  if(SearchVector.empty())
17999  {
18000  Utilities->CallLogPop(1149);
18001  return;
18002  }
18003  for(unsigned int b = 0; b < SearchVector.size(); b++)
18004  {
18007  PrefDirRoute);
18008  }
18009  Utilities->CallLogPop(346);
18010 }
18011 
18012 // ---------------------------------------------------------------------------
18013 
18014 void TOneRoute::SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
18015 /*
18016  Sets all element values in the RouteFlashVector (member of class TRouteFlash - defined in TOneRoute, of which
18017  TOneRoute has one member called RouteFlash) from the SearchVector. TRouteFlashElement is also a class defined in
18018  TOneRoute.
18019 */
18020 {
18021  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteFlashValues," + AnsiString((short)AutoSigsFlag) + "," +
18022  AnsiString((short)PrefDirRoute));
18023  RouteFlash.RouteFlashVector.clear();
18024  TRouteFlashElement RouteFlashElement;
18025 
18026  for(unsigned int b = 0; b < SearchVector.size(); b++)
18027  {
18028  int H = GetFixedSearchElementAt(11, b).HLoc;
18029  int V = GetFixedSearchElementAt(12, b).VLoc;
18031  RouteFlashElement.OverlayGraphic = GetModifiableSearchElementAt(6, b).GetRouteGraphicPtr(AutoSigsFlag, PrefDirRoute);
18032  RouteFlashElement.HLoc = H;
18033  RouteFlashElement.VLoc = V;
18035  RouteFlash.RouteFlashVector.push_back(RouteFlashElement);
18036  }
18037  Utilities->CallLogPop(348);
18038 }
18039 
18040 // ---------------------------------------------------------------------------
18041 
18042 void TOneRoute::SetLCChangeValues(int Caller, bool PrefDirRoute) //used when setting routes to start any included LC's lowering
18043 {
18044  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCChangeValues," + AnsiString((short)PrefDirRoute));
18045  if(!PrefDirVector.empty())
18046  {
18047  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
18048  {
18049  int H = PrefDirPtr->HLoc;
18050  int V = PrefDirPtr->VLoc;
18051  // check for any LCs that are closed to trains & set the flash values and store in the vector
18052  if(Track->IsLCAtHV(39, H, V))
18053  {
18054  if(Track->IsLCBarrierUpAtHV(0, H, V))
18055  {
18056  Track->LCChangeFlag = true;
18057  TTrack::TActiveLevelCrossing CLC; // constructor sets ReducedTimePenalty to false
18058  CLC.HLoc = H;
18059  CLC.VLoc = V;
18061  CLC.BaseElementSpeedTag = PrefDirPtr->SpeedTag;
18064  if(PrefDirRoute)
18065  {
18066  CLC.TypeOfRoute = 1;
18067  }
18068  Track->SetLinkedLevelCrossingBarrierAttributes(1, H, V, 2); // set attr to 2 for changing state
18069  Track->ChangingLCVector.push_back(CLC);
18070  }
18071  }
18072  }
18073  }
18074  Utilities->CallLogPop(1948);
18075 }
18076 
18077 // ---------------------------------------------------------------------------
18078 
18080 /*
18081  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
18082  checks first whether the OverlayPlotted flag is set and if not plots the OverlayGraphic for all
18083  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
18084  is set. The OverlayGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
18085 */
18086 {
18087  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOverlay");
18088  if(!OverlayPlotted)
18089  {
18090  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
18091  {
18092  if(Track->TrackElementAt(123, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
18093  {
18094  continue;
18095  }
18096  Display->PlotOutput(20, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OverlayGraphic);
18097  Display->Update();
18098  }
18099  OverlayPlotted = true;
18100  }
18101  Utilities->CallLogPop(349);
18102 }
18103 
18104 // ---------------------------------------------------------------------------
18105 
18107 /*
18108  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
18109  checks first whether the OverlayPlotted flag is set and if so plots the OriginalGraphic for all
18110  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
18111  is reset. The OriginalGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
18112 */
18113 {
18114  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOriginal");
18115  if(OverlayPlotted)
18116  {
18117  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
18118  {
18119  if(Track->TrackElementAt(124, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
18120  {
18121  continue;
18122  }
18123  Display->PlotOutput(21, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OriginalGraphic);
18124  Display->Update();
18125  }
18126  OverlayPlotted = false;
18127  }
18128  Utilities->CallLogPop(350);
18129 }
18130 
18131 // ---------------------------------------------------------------------------
18132 
18133 bool TOneRoute::SignalHasFailed(int Caller) //added at v2.13.0
18134 {
18135 /*enter with SearchVector fully populated & with a legitimate route found, return true for failure.
18136 Look along SearchVector backwards, skip first signal found (i.e. last in route), but for all others
18137 including first signal in route offer chance to fail (since they all change aspect), but if find any failed point
18138 where no route available (i.e. a dead end, points checked after search in PointsToBeChanged) then return false - i.e. don't
18139 allow signal failure in an unviable route. If fail (i.e. prior to returning true), alter graphic, send
18140 messages, and allocate a repair time similar to points) */
18141  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SignalHasFailed");
18142  if(Utilities->DelayMode == Nil)
18143  {
18144  Utilities->CallLogPop(2528);
18145  return(false);
18146  }
18147  bool FirstSignalFound = false;
18148  for(TPrefDirVector::iterator PDVIt = SearchVector.end() - 1; PDVIt >= SearchVector.begin(); PDVIt--)
18149  {
18150  TTrackElement &TE = Track->TrackElementAt(1530, PDVIt->TrackVectorPosition);
18151 //check for a failed point where needs to change to make the route
18152 //shouldn't be any but check to be safe
18153  int Attr = TE.Attribute;
18154  if(PDVIt->TrackType == Points)
18155  {
18156  if((PDVIt->ELinkPos == 1) || (PDVIt->XLinkPos == 1)) // 1=want to go straight
18157  {
18158  if(Attr == 1) //currently set to diverge
18159  {
18160  if(TE.Failed)
18161  {
18162  Utilities->CallLogPop(2529);
18163  return(false); //return without further checking
18164  }
18165  }
18166  }
18167  else if((PDVIt->ELinkPos == 3) || (PDVIt->XLinkPos == 3)) // 3=want to diverge
18168  {
18169  if(Attr == 0) //currently set to go straight
18170  {
18171  if(TE.Failed)
18172  {
18173  Utilities->CallLogPop(2530);
18174  return(false); //return without further checking
18175  }
18176  }
18177  }
18178  }
18179  if((PDVIt->Config[PDVIt->XLinkPos] == Signal) && (TE.SigAspect == TTrackElement::GroundSignal))
18180  {
18181  continue; //ground signals don't fail
18182  }
18183  if(!FirstSignalFound && (PDVIt->Config[PDVIt->XLinkPos] == Signal))
18184  {
18185  FirstSignalFound = true; //if being called then this is the calling on signal and don't want that to fail
18186  continue;
18187  }
18188  else if(FirstSignalFound && (PDVIt->Config[PDVIt->XLinkPos] == Signal))
18189  {
18190  if((random(Utilities->SignalChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice
18191  {
18193  IFE.TVPos = PDVIt->TrackVectorPosition;
18194  TE.Failed = true;
18195  TE.Attribute = 0; //stop aspect
18196  Display->WarningLog(22, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal failed at " + TE.ElementID);
18197  PerfLogForm->PerformanceLog(45, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Signal failed at " + TE.ElementID);
18198  TrainController->StopTTClockMessage(132, "Signal at " + TE.ElementID +
18199  " failed when changing aspect.\nTrains can only pass under signaller control.");
18200  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
18201 //set repair time, random value in minutes between 10 and 179
18202  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime); //between 10 and 179 minutes at random
18203  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
18204  IFE.RepairTime = RepairTime;
18206  Track->FailedSignalsVector.push_back(IFE);
18208  int RouteNumber; //not used
18209  if(AllRoutes->GetRouteTypeAndNumber(41, IFE.TVPos, 0, RouteNumber) != TAllRoutes::NoRoute) //otherwise Attribute already 0 so will plot red
18210  { // 0 for LinkPos ok as a signal so only one track
18211  AllRoutes->AllRoutesVector.at(RouteNumber).SetRouteSignals(12);
18212  }
18213  Utilities->CallLogPop(2535);
18214  return(true); //return so only allow one failure per route
18215  }
18216  }
18217  }
18218  Utilities->CallLogPop(2531);
18219  return(false);
18220 }
18221 
18222 // ---------------------------------------------------------------------------
18223 // ---------------------------------------------------------------------------
18224 
18225 const TOneRoute &TAllRoutes::GetFixedRouteAt(int Caller, int At) const
18226 {
18227  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAt," + AnsiString(At));
18228  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
18229  {
18230  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetFixedRouteAt");
18231  }
18232  Utilities->CallLogPop(120);
18233  return(AllRoutesVector.at(At));
18234 }
18235 
18236 // ---------------------------------------------------------------------------
18237 
18239 {
18240  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteAt," + AnsiString(At));
18241  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
18242  {
18243  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableRouteAt");
18244  }
18245  Utilities->CallLogPop(121);
18246  return(AllRoutesVector.at(At));
18247 }
18248 
18249 // ---------------------------------------------------------------------------
18250 
18251 void TAllRoutes::MarkAllRoutes(int Caller, TDisplay *Disp)
18252 /*
18253  Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir false.
18254 */
18255 {
18256  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkAllRoutes");
18257  for(unsigned int a = 0; a < AllRoutesSize(); a++)
18258  {
18259  GetFixedRouteAt(62, a).PrefDirMarker(7, RouteCall, false, Disp);
18260  }
18261  Utilities->CallLogPop(351);
18262 }
18263 
18264 // ---------------------------------------------------------------------------
18265 
18266 void TAllRoutes::WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
18267 {
18268  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteAllRoutesToImage");
18269  for(unsigned int a = 0; a < AllRoutesSize(); a++)
18270  {
18271  GetFixedRouteAt(166, a).RouteImageMarker(0, Bitmap);
18272  }
18273  Utilities->CallLogPop(1706);
18274 }
18275 
18276 // ---------------------------------------------------------------------------
18277 
18278 bool TAllRoutes::GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
18279 /*
18280  Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is present in
18281  that route. The ReturnFlag value indicates InRouteTrue (success), InRouteFalse (failure), or NotInRoute.
18282  Messages are given in GetRouteTruncateElement. If successful the route is truncated at and including
18283  the element that matches H & V. If PrefDirRoute ensure only truncate to a signal, else prevent
18284  truncation to a crossover, bridge or points, also prevent route being left less than 2 elements in
18285  length (train length).
18286 */
18287 {
18288  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAllRoutesTruncateElement," + AnsiString(HLoc) + "," +
18289  AnsiString(VLoc) + "," + AnsiString((short)PrefDirRoute));
18290  for(unsigned int a = 0; a < AllRoutesSize(); a++)
18291  {
18292  TTruncateReturnType ReturnFlag;
18293  RouteTruncateFlag = true;
18294 // used in SetRearwardsSignalsReturnFalseForTrain (called by GetRouteTruncateElement) to skip continuation & buffer attribute change
18295  GetModifiableRouteAt(7, a).GetRouteTruncateElement(0, HLoc, VLoc, PrefDirRoute, ReturnFlag);
18296  RouteTruncateFlag = false;
18297  if(ReturnFlag == NotInRoute)
18298  {
18299  continue;
18300  }
18301  else if(ReturnFlag == InRouteTrue)
18302  {
18303  Utilities->CallLogPop(352);
18304  return(true);
18305  }
18306  else if(ReturnFlag == InRouteFalse)
18307  {
18308  Utilities->CallLogPop(353);
18309  return(false);
18310  }
18311  }
18312  Utilities->CallLogPop(354);
18313  return(false);
18314 }
18315 
18316 // ---------------------------------------------------------------------------
18317 
18318 bool TAllRoutes::TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
18319 /*
18320  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)
18321  is found it returns true (for crossovers & points returns true whichever track the route is on), else returns false.
18322 */
18323 {
18324  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackIsInARoute," + AnsiString(TrackVectorPosition) + "," +
18325  AnsiString(LinkPos));
18326  if(TrackVectorPosition == -1) // allows for continuation entries & exits
18327  {
18328  Utilities->CallLogPop(355);
18329  return(false);
18330  }
18331  THVPair Route2MultiMapKeyPair;
18332 
18333  Route2MultiMapKeyPair.first = Track->TrackElementAt(125, TrackVectorPosition).HLoc;
18334  Route2MultiMapKeyPair.second = Track->TrackElementAt(126, TrackVectorPosition).VLoc;
18335  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
18336  TRoute2MultiMapIterator Route2MultiMapIterator;
18337 
18338  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0) // none found
18339  {
18340  Utilities->CallLogPop(356);
18341  return(false);
18342  }
18343  if(Track->TrackElementAt(706, TrackVectorPosition).TrackType != Bridge) // if not a bridge doesn't matter which track the route is on
18344  {
18345  Utilities->CallLogPop(1422);
18346  return(true);
18347  }
18348  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
18349  {
18350  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
18351 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
18352 // realised after writing this that can't be points as would have been covered above, but leave anyway
18353  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(64, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(88,
18354  Route2MultiMapIterator->second.second);
18355  EntryLinkPos = PrefDirElement1.ELinkPos;
18356  ExitLinkPos = PrefDirElement1.XLinkPos;
18357  EntryLink = PrefDirElement1.Link[EntryLinkPos];
18358  ExitLink = PrefDirElement1.Link[ExitLinkPos];
18359  if(EntryLink == Track->TrackElementAt(127, TrackVectorPosition).Link[LinkPos])
18360  {
18361  Utilities->CallLogPop(357);
18362  return(true);
18363  }
18364  if(ExitLink == Track->TrackElementAt(128, TrackVectorPosition).Link[LinkPos])
18365  {
18366  Utilities->CallLogPop(358);
18367  return(true);
18368  }
18369  }
18370  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2) // if both tracks in route then must return true
18371  {
18372  Utilities->CallLogPop(1423);
18373  return(true);
18374  }
18375  Utilities->CallLogPop(363);
18376  return(false); // none found
18377 }
18378 
18379 // ---------------------------------------------------------------------------
18380 
18381 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap* &EXGraphicPtr,
18382  Graphics::TBitmap* &EntryDirectionGraphicPtr)
18383 /*
18384  Examines Route2MultiMap and if finds the element at TrackVectorPosition with LinkPos (can be entry or exit) returns the appropriate route
18385  type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute. If element not found then NoRoute is returned. If element is in a route then the EXGraphicPtr
18386  is returned, and if either the start or end of a route then the correct EntryDirectionGraphicPtr is returned, else a transparent element is returned.
18387  Function is used in TrainUnit for retaining AutoSigsRoutes but erasing others after train passes, and for picking up the correct background graphics
18388  for replotting of AutoSigsRoutes.
18389 */
18390 {
18391  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndGraphics," + AnsiString(TrackVectorPosition) + "," +
18392  AnsiString(LinkPos));
18393  EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
18394  EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
18395  if(TrackVectorPosition == -1)
18396  {
18397  Utilities->CallLogPop(364);
18398  return(NoRoute); // allows for continuation entries & exits
18399  }
18400  THVPair Route2MultiMapKeyPair;
18401 
18402  Route2MultiMapKeyPair.first = Track->TrackElementAt(133, TrackVectorPosition).HLoc;
18403  Route2MultiMapKeyPair.second = Track->TrackElementAt(134, TrackVectorPosition).VLoc;
18404  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
18405  TRoute2MultiMapIterator Route2MultiMapIterator;
18406 
18407  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
18408  {
18409  Utilities->CallLogPop(365);
18410  return(NoRoute); // none found
18411  }
18412  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
18413  {
18414  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
18415 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
18416  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(73, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(97,
18417  Route2MultiMapIterator->second.second);
18418  EntryLinkPos = PrefDirElement1.ELinkPos;
18419  ExitLinkPos = PrefDirElement1.XLinkPos;
18420  EntryLink = PrefDirElement1.Link[EntryLinkPos];
18421  ExitLink = PrefDirElement1.Link[ExitLinkPos];
18422  if(EntryLink == Track->TrackElementAt(135, TrackVectorPosition).Link[LinkPos])
18423  {
18424  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
18425  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(74,
18426  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
18427  {
18428  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
18429  }
18430  if(PrefDirElement1.AutoSignals)
18431  {
18432  Utilities->CallLogPop(366);
18433  return(AutoSigsRoute);
18434  }
18435  else
18436  {
18437  Utilities->CallLogPop(367);
18438  return(NotAutoSigsRoute);
18439  }
18440  }
18441  if(ExitLink == Track->TrackElementAt(136, TrackVectorPosition).Link[LinkPos])
18442  {
18443  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
18444  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(75,
18445  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
18446  {
18447  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
18448  }
18449  if(PrefDirElement1.AutoSignals)
18450  {
18451  Utilities->CallLogPop(368);
18452  return(AutoSigsRoute);
18453  }
18454  else
18455  {
18456  Utilities->CallLogPop(369);
18457  return(NotAutoSigsRoute);
18458  }
18459  }
18460  }
18461  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
18462  {
18463  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
18464  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
18465 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
18466  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(76, ItPair.first->second.first).GetFixedPrefDirElementAt(98, ItPair.first->second.second);
18467  EntryLinkPos = PrefDirElement2.ELinkPos;
18468  ExitLinkPos = PrefDirElement2.XLinkPos;
18469  EntryLink = PrefDirElement2.Link[EntryLinkPos];
18470  ExitLink = PrefDirElement2.Link[ExitLinkPos];
18471  if(EntryLink == Track->TrackElementAt(137, TrackVectorPosition).Link[LinkPos])
18472  {
18473  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
18474  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(77, ItPair.first->second.first).PrefDirSize() - 1))
18475  {
18476  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
18477  }
18478  if(PrefDirElement2.AutoSignals)
18479  {
18480  Utilities->CallLogPop(370);
18481  return(AutoSigsRoute);
18482  }
18483  else
18484  {
18485  Utilities->CallLogPop(371);
18486  return(NotAutoSigsRoute);
18487  }
18488  }
18489  if(ExitLink == Track->TrackElementAt(138, TrackVectorPosition).Link[LinkPos])
18490  {
18491  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
18492  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(78, ItPair.first->second.first).PrefDirSize() - 1))
18493  {
18494  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
18495  }
18496  if(PrefDirElement2.AutoSignals)
18497  {
18498  Utilities->CallLogPop(372);
18499  return(AutoSigsRoute);
18500  }
18501  else
18502  {
18503  Utilities->CallLogPop(373);
18504  return(NotAutoSigsRoute);
18505  }
18506  }
18507  ItPair.second--; // the second iterator points one past the last matching value
18508  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(79, ItPair.second->second.first).GetFixedPrefDirElementAt(99, ItPair.second->second.second);
18509  EntryLinkPos = PrefDirElement3.ELinkPos;
18510  ExitLinkPos = PrefDirElement3.XLinkPos;
18511  EntryLink = PrefDirElement3.Link[EntryLinkPos];
18512  ExitLink = PrefDirElement3.Link[ExitLinkPos];
18513  if(EntryLink == Track->TrackElementAt(139, TrackVectorPosition).Link[LinkPos])
18514  {
18515  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
18516  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(80, ItPair.second->second.first).PrefDirSize() - 1))
18517  {
18518  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
18519  }
18520  if(PrefDirElement3.AutoSignals)
18521  {
18522  Utilities->CallLogPop(374);
18523  return(AutoSigsRoute);
18524  }
18525  else
18526  {
18527  Utilities->CallLogPop(375);
18528  return(NotAutoSigsRoute);
18529  }
18530  }
18531  if(ExitLink == Track->TrackElementAt(140, TrackVectorPosition).Link[LinkPos])
18532  {
18533  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
18534  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(81, ItPair.second->second.first).PrefDirSize() - 1))
18535  {
18536  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
18537  }
18538  if(PrefDirElement3.AutoSignals)
18539  {
18540  Utilities->CallLogPop(376);
18541  return(AutoSigsRoute);
18542  }
18543  else
18544  {
18545  Utilities->CallLogPop(377);
18546  return(NotAutoSigsRoute);
18547  }
18548  }
18549  }
18550  Utilities->CallLogPop(378);
18551  return(NoRoute); // none found
18552 }
18553 
18554 // ---------------------------------------------------------------------------
18555 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
18556 /*
18557  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit) is found returns the appropriate
18558  route type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute and number.
18559 */
18560 {
18561  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndNumber," + AnsiString(TrackVectorPosition) + "," +
18562  AnsiString(LinkPos));
18563  if(TrackVectorPosition == -1)
18564  {
18565  RouteNumber = -1;
18566  Utilities->CallLogPop(379);
18567  return(NoRoute); // allows for continuation & buffer entries & exits
18568  }
18569  THVPair Route2MultiMapKeyPair;
18570 
18571  Route2MultiMapKeyPair.first = Track->TrackElementAt(141, TrackVectorPosition).HLoc;
18572  Route2MultiMapKeyPair.second = Track->TrackElementAt(142, TrackVectorPosition).VLoc;
18573  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
18574  TRoute2MultiMapIterator Route2MultiMapIterator;
18575 
18576  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
18577  {
18578  RouteNumber = -1;
18579  Utilities->CallLogPop(380);
18580  return(NoRoute); // none found
18581  }
18582  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
18583  {
18584  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
18585 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
18586  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(82, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(100,
18587  Route2MultiMapIterator->second.second);
18588  EntryLinkPos = PrefDirElement1.ELinkPos;
18589  ExitLinkPos = PrefDirElement1.XLinkPos;
18590  EntryLink = PrefDirElement1.Link[EntryLinkPos];
18591  ExitLink = PrefDirElement1.Link[ExitLinkPos];
18592  if(EntryLink == Track->TrackElementAt(143, TrackVectorPosition).Link[LinkPos])
18593  {
18594  RouteNumber = Route2MultiMapIterator->second.first;
18595  if(PrefDirElement1.AutoSignals)
18596  {
18597  Utilities->CallLogPop(381);
18598  return(AutoSigsRoute);
18599  }
18600  else
18601  {
18602  Utilities->CallLogPop(382);
18603  return(NotAutoSigsRoute);
18604  }
18605  }
18606  if(ExitLink == Track->TrackElementAt(144, TrackVectorPosition).Link[LinkPos])
18607  {
18608  RouteNumber = Route2MultiMapIterator->second.first;
18609  if(PrefDirElement1.AutoSignals)
18610  {
18611  Utilities->CallLogPop(383);
18612  return(AutoSigsRoute);
18613  }
18614  else
18615  {
18616  Utilities->CallLogPop(384);
18617  return(NotAutoSigsRoute);
18618  }
18619  }
18620  }
18621  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
18622  {
18623  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
18624  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
18625 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
18626  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(83, ItPair.first->second.first).GetFixedPrefDirElementAt(101, ItPair.first->second.second);
18627  EntryLinkPos = PrefDirElement2.ELinkPos;
18628  ExitLinkPos = PrefDirElement2.XLinkPos;
18629  EntryLink = PrefDirElement2.Link[EntryLinkPos];
18630  ExitLink = PrefDirElement2.Link[ExitLinkPos];
18631  if(EntryLink == Track->TrackElementAt(145, TrackVectorPosition).Link[LinkPos])
18632  {
18633  RouteNumber = ItPair.first->second.first;
18634  if(PrefDirElement2.AutoSignals)
18635  {
18636  Utilities->CallLogPop(385);
18637  return(AutoSigsRoute);
18638  }
18639  else
18640  {
18641  Utilities->CallLogPop(386);
18642  return(NotAutoSigsRoute);
18643  }
18644  }
18645  if(ExitLink == Track->TrackElementAt(146, TrackVectorPosition).Link[LinkPos])
18646  {
18647  RouteNumber = ItPair.first->second.first;
18648  if(PrefDirElement2.AutoSignals)
18649  {
18650  Utilities->CallLogPop(387);
18651  return(AutoSigsRoute);
18652  }
18653  else
18654  {
18655  Utilities->CallLogPop(388);
18656  return(NotAutoSigsRoute);
18657  }
18658  }
18659  ItPair.second--; // the second iterator points one past the last matching value
18660  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(84, ItPair.second->second.first).GetFixedPrefDirElementAt(102, ItPair.second->second.second);
18661  EntryLinkPos = PrefDirElement3.ELinkPos;
18662  ExitLinkPos = PrefDirElement3.XLinkPos;
18663  EntryLink = PrefDirElement3.Link[EntryLinkPos];
18664  ExitLink = PrefDirElement3.Link[ExitLinkPos];
18665  if(EntryLink == Track->TrackElementAt(147, TrackVectorPosition).Link[LinkPos])
18666  {
18667  RouteNumber = ItPair.second->second.first;
18668  if(PrefDirElement3.AutoSignals)
18669  {
18670  Utilities->CallLogPop(389);
18671  return(AutoSigsRoute);
18672  }
18673  else
18674  {
18675  Utilities->CallLogPop(390);
18676  return(NotAutoSigsRoute);
18677  }
18678  }
18679  if(ExitLink == Track->TrackElementAt(148, TrackVectorPosition).Link[LinkPos])
18680  {
18681  RouteNumber = ItPair.second->second.first;
18682  if(PrefDirElement3.AutoSignals)
18683  {
18684  Utilities->CallLogPop(391);
18685  return(AutoSigsRoute);
18686  }
18687  else
18688  {
18689  Utilities->CallLogPop(392);
18690  return(NotAutoSigsRoute);
18691  }
18692  }
18693  }
18694  RouteNumber = -1;
18695  Utilities->CallLogPop(393);
18696  return(NoRoute); // none found
18697 }
18698 
18699 // ---------------------------------------------------------------------------
18700 
18701 void TAllRoutes::StoreOneRoute(int Caller, TOneRoute *Route)
18702 /*
18703  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector, which, since it is the last to be added, will have
18704  a RouteNumber of AllRoutesSize() - 1. Then each element of the new route is added in turn using AddRouteElement,
18705  which uses HLoc, VLoc, ELink and RouteNumber to provide the information necessary to insert it into both PrefDirVector
18706  and Route2MultiMap.
18707 */
18708 {
18709  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRoute");
18710  TOneRoute EmptyRoute;
18711 
18712  EmptyRoute.RouteID = NextRouteID;
18713  NextRouteID++;
18714 
18715  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
18716  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
18717  {
18718  AddRouteElement(0, Route->GetFixedPrefDirElementAt(127, x).HLoc, Route->GetFixedPrefDirElementAt(128, x).VLoc,
18719  Route->GetFixedPrefDirElementAt(129, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(130, x));
18720  }
18721  int FirstVecPos = Route->GetFixedPrefDirElementAt(199, 0).TrackVectorPosition;
18722  int LastVecPos = Route->GetFixedPrefDirElementAt(200, (Route->PrefDirSize()) - 1).TrackVectorPosition;
18723 
18724  TrainController->LogEvent("StoreOneRoute," + AnsiString(EmptyRoute.RouteID) + "," + AnsiString(FirstVecPos) + "," + AnsiString(LastVecPos));
18725  Utilities->CallLogPop(394);
18726 }
18727 
18728 // ---------------------------------------------------------------------------
18729 
18731 /*
18732  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load. For this the RouteID
18733  that is already in Route is used.
18734 */
18735 {
18736  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRouteAfterSessionLoad");
18737  TOneRoute EmptyRoute;
18738 
18739  EmptyRoute.RouteID = Route->RouteID;
18740 
18741  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
18742  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
18743  {
18744  AddRouteElement(3, Route->GetFixedPrefDirElementAt(189, x).HLoc, Route->GetFixedPrefDirElementAt(190, x).VLoc,
18745  Route->GetFixedPrefDirElementAt(191, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(192, x));
18746  }
18747  Utilities->CallLogPop(1579);
18748 }
18749 
18750 // ---------------------------------------------------------------------------
18751 
18752 void TAllRoutes::ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
18753 /*
18754  When attaching a new route section to an existing route, it is sometimes necessary to erase the
18755  original route and create a new composite route. This function Erases all elements in the route
18756  at RouteNumber using TAllRoutes->RemoveRouteElement to clear elements from Route2MultiMap and
18757  from the PrefDirVector. Since all elements for the route are removed RemoveRouteElement also
18758  clears the Route from AllRoutesVector. Route numbers are decremented in the map for route numbers
18759  that are greater than the route number that is removed. The LockedRouteVector as also searched
18760  and if any relate to the route that has been cleared they are erased too, but the fact that one
18761  has been found is recorded so that it can be re-established later.
18762 */
18763 {
18764  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearRouteDuringRouteBuildingAt," + AnsiString(RouteNumber));
18765  THVPair Route2MultiMapKeyPair;
18766  TRoute2MultiMapEntry Route2MultiMapEntry;
18767  TRoute2MultiMapIterator Route2MultiMapIterator;
18768 
18769 // need to check LockedVector first, and erase it if it's the route to be cleared, and to reinstate it as a new locked route with the same
18770 // values (except RouteNumber) when the new route is established (in ConvertAndAdd...).
18771 // If clear all route elements first then when the last is cleared the LockedVector.RouteNumber values are decremented if they are higher
18772 // then the cleared route number (by RemoveRouteElement), and one of the new values may be the same number as the old cleared route number.
18773 // If so the locked route is removed from the locked vector and is lost.
18774  LockedRouteTruncateTrackVectorPosition = 0;
18775  LockedRouteLastTrackVectorPosition = 0;
18776  LockedRouteLastXLinkPos = 0;
18777  LockedRouteLockStartTime = TDateTime(0);
18778  if(!LockedRouteVector.empty())
18779  {
18780  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
18781  {
18782  if(LRVIT->RouteNumber == RouteNumber)
18783  {
18784  LockedRouteTruncateTrackVectorPosition = LRVIT->TruncateTrackVectorPosition;
18785  LockedRouteLastTrackVectorPosition = LRVIT->LastTrackVectorPosition;
18786  LockedRouteLastXLinkPos = LRVIT->LastXLinkPos;
18787  LockedRouteLockStartTime = LRVIT->LockStartTime;
18788  LockedRouteFoundDuringRouteBuilding = true;
18789  LockedRouteVector.erase(LRVIT);
18790  }
18791  }
18792  }
18793  for(int x = (AllRoutes->GetFixedRouteAt(109, RouteNumber).PrefDirSize()) - 1; x >= 0; x--)
18794  {
18795  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(110, RouteNumber).GetFixedPrefDirElementAt(131, x);
18796  AllRoutes->RemoveRouteElement(7, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.GetELink());
18797  }
18798  Utilities->CallLogPop(395);
18799 }
18800 
18801 // ---------------------------------------------------------------------------
18802 
18804  TRoute2MultiMapIterator &Route2MultiMapIterator)
18805 /*
18806  Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H, V and ELink.
18807  Also returned as a reference is an iterator to the found element in the map to assist in erasing it. Called by
18808  TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink). Note that only need ELink (as well as H & V) to
18809  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different. Messages
18810  are given for failure.
18811 */
18812 {
18813  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRoutePairFromRoute2MultiMap," + AnsiString(HLoc) + "," +
18814  AnsiString(VLoc) + "," + AnsiString(ELink));
18815  TRouteElementPair ReturnPair;
18816 
18817  ReturnPair.first = -1;
18818  ReturnPair.second = 0;
18819  THVPair Route2MultiMapKeyPair;
18820 
18821  Route2MultiMapKeyPair.first = HLoc;
18822  Route2MultiMapKeyPair.second = VLoc;
18823  TRoute2MultiMapEntry Route2MultiMapEntry;
18824 
18825  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
18826  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
18827 
18828  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
18829  Route2MultiMapIterator = ItPair.first;
18830 
18831  if(ItPair.first == ItPair.second)
18832  {
18833  throw Exception("Failed to find Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc);
18834  }
18835  if(GetFixedRouteAt(111, ItPair.first->second.first).GetFixedPrefDirElementAt(132, ItPair.first->second.second).GetELink() == ELink)
18836  {
18837  ReturnPair.first = ItPair.first->second.first;
18838  ReturnPair.second = ItPair.first->second.second;
18839  Route2MultiMapIterator = ItPair.first;
18840  Utilities->CallLogPop(396);
18841  return(ReturnPair);
18842  }
18843  ItPair.first++;
18844  if(ItPair.first == ItPair.second)
18845  {
18846  throw Exception("Found Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc + " but failed to find required element");
18847  }
18848  if(GetFixedRouteAt(112, ItPair.first->second.first).GetFixedPrefDirElementAt(133, ItPair.first->second.second).GetELink() == ELink)
18849  {
18850  ReturnPair.first = ItPair.first->second.first;
18851  ReturnPair.second = ItPair.first->second.second;
18852  Route2MultiMapIterator = ItPair.first;
18853  Utilities->CallLogPop(397);
18854  return(ReturnPair);
18855  }
18856  Utilities->CallLogPop(398);
18857  return(ReturnPair);
18858 }
18859 
18860 // ---------------------------------------------------------------------------
18861 
18862 bool TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber) // new at v1.2.0
18863 /*
18864  Similar to above but returns a bool and no errors are reported for no route or element at H&V etc.
18865  Examines Route2MultiMap and returns true if a route is found with the passed values of H, V and ELink.
18866  RouteNumber (route position in AllRoutes vector is returned as a reference.
18867  Called by TTrain::CheckAndCancelRouteForWrongEndEntry. Note that only need ELink (as well as H & V) to
18868  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different.
18869 */
18870 {
18871  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRouteNumberFromRoute2MultiMapNoErrors," + AnsiString(HLoc) + "," +
18872  AnsiString(VLoc) + "," + AnsiString(ELink));
18873  THVPair Route2MultiMapKeyPair;
18874 
18875  Route2MultiMapKeyPair.first = HLoc;
18876  Route2MultiMapKeyPair.second = VLoc;
18877  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
18878 
18879  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
18880 
18881  if(ItPair.first == ItPair.second)
18882  {
18883  RouteNumber = -1;
18884  Utilities->CallLogPop(2032);
18885  return(false);
18886  }
18887  if(GetFixedRouteAt(205, ItPair.first->second.first).GetFixedPrefDirElementAt(241, ItPair.first->second.second).GetELink() == ELink)
18888  {
18889  RouteNumber = ItPair.first->second.first;
18890  Utilities->CallLogPop(2033);
18891  return(true);
18892  }
18893  ItPair.first++;
18894 
18895  if(ItPair.first == ItPair.second)
18896  {
18897  RouteNumber = -1;
18898  Utilities->CallLogPop(2034);
18899  return(false);
18900  }
18901  if(GetFixedRouteAt(206, ItPair.first->second.first).GetFixedPrefDirElementAt(242, ItPair.first->second.second).GetELink() == ELink)
18902  {
18903  RouteNumber = ItPair.first->second.first;
18904  Utilities->CallLogPop(2035);
18905  return(true);
18906  }
18907  RouteNumber = -1;
18908  Utilities->CallLogPop(2036);
18909  return(false);
18910 }
18911 
18912 // ---------------------------------------------------------------------------
18913 
18914 void TAllRoutes::Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
18915 /*
18916  Elink needed in case it's a bridge, & need to know whether the found element is on this route or not. First check if an
18917  entry in the map already exists at H & V, and if so check that it's a bridge with existing route on other track.
18918  That being so insert the new element. If it's not a bridge, or the route has the same ELink value as the element to
18919  be inserted, give appropriate messages. If there isn't an element at H & V already in the map insert it.
18920  Called by TAllRoutes::AddRouteElement.
18921 */
18922 {
18923  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Route2MultiMapInsert," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
18924  "," + AnsiString(ELinkIn) + "," + AnsiString(RouteNumber) + "," + AnsiString(RouteElementNumber));
18925  THVPair Route2MultiMapKeyPair;
18926 
18927  Route2MultiMapKeyPair.first = HLoc;
18928  Route2MultiMapKeyPair.second = VLoc;
18929  TRoute2MultiMapEntry Route2MultiMapEntry;
18930 
18931  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
18932  TRouteElementPair RouteElementPair;
18933 
18934  RouteElementPair.first = RouteNumber;
18935  RouteElementPair.second = RouteElementNumber;
18936  Route2MultiMapEntry.second = RouteElementPair;
18937 
18938  if(Route2MultiMap.find(Route2MultiMapKeyPair) != Route2MultiMap.end())
18939  // true for element at H&V already included in map, has to be a bridge with existing route on opposite track to be valid
18940  {
18941  if(GetFixedRouteAt(113, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(134,
18942  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).GetELink() != ELinkIn)
18943  // element already at H&V has different ELink to element to be inserted, so must be a bridge with existing route on opposite treack
18944  {
18945  if(GetFixedRouteAt(114, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(135,
18946  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).TrackType != Bridge)
18947  {
18948  throw Exception("Error, bridge expected in Route2MultiMapInsert but not, at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
18949  }
18950  Route2MultiMap.insert(Route2MultiMapEntry); // insert bridge into map again but now with the new track as part of required route
18951  }
18952  else
18953  // same ELink so have an error
18954  {
18955  throw Exception("Error, route map entry found in Route2MultiMapInsert at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
18956  }
18957  }
18958  else
18959  {
18960  Route2MultiMap.insert(Route2MultiMapEntry);
18961  }
18962 // element at H&V not found in map so insert it
18963  Utilities->CallLogPop(399);
18964 }
18965 
18966 // ---------------------------------------------------------------------------
18967 
18969 /*
18970  Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function return
18971  and the second in the reference SecondPair. If there's only one then it's the function return
18972 */
18973 {
18974  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteElementDataFromRoute2MultiMap," + AnsiString(HLoc) + "," +
18975  AnsiString(VLoc));
18977 
18978  TempPair.first = -1;
18979  TempPair.second = 0;
18980  SecondPair = TempPair;
18981  TRoute2MultiMapIterator Route2MultiMapIterator;
18982  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItRange;
18983  THVPair Route2MultiMapKeyPair;
18984 
18985  Route2MultiMapKeyPair.first = HLoc;
18986  Route2MultiMapKeyPair.second = VLoc;
18987  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
18988  {
18989  Utilities->CallLogPop(400);
18990  return(TempPair);
18991  }
18992  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
18993  {
18994  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
18995  Utilities->CallLogPop(401);
18996  return(Route2MultiMapIterator->second);
18997  }
18998  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
18999  {
19000  ItRange = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
19001  TempPair = ItRange.first->second;
19002  SecondPair = (--ItRange.second)->second; // 2nd iterator points past the last value
19003  Utilities->CallLogPop(402);
19004  return(TempPair);
19005  }
19006  Utilities->CallLogPop(403);
19007  return(TempPair);
19008 }
19009 
19010 // ---------------------------------------------------------------------------
19011 
19012 void TAllRoutes::CheckMapAndRoutes(int Caller) // test
19013 /*
19014  Checks equivalence for each route between entries in PrefDirVector and those in Route2MultiMap, and also that the size
19015  of the multimap and the sum of the sizes of all PrefDirVectors is the same.
19016 */
19017 {
19018  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndRoutes");
19019  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
19020  {
19021  for(unsigned int b = 0; b < AllRoutes->GetFixedRouteAt(115, a).PrefDirSize(); b++)
19022  {
19023  TPrefDirElement CheckElement = AllRoutes->GetFixedRouteAt(116, a).GetFixedPrefDirElementAt(136, b);
19024  TAllRoutes::TRouteElementPair SecondPair;
19025  TRouteElementPair RouteElementPair = GetRouteElementDataFromRoute2MultiMap(8, CheckElement.HLoc, CheckElement.VLoc, SecondPair);
19026  if(RouteElementPair.first == -1)
19027  // failed to find element in multimap
19028  {
19029  throw Exception("CheckMapAndRoutes Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
19030  " in Route2MultiMap, Caller=" + (AnsiString)Caller);
19031  }
19032  if((RouteElementPair.first != (int)a) && (SecondPair.first != (int)a))
19033  // neither pair has expected route number
19034  {
19035  throw Exception("CheckMapAndRoutes Error - RouteNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
19036  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)RouteElementPair.first + " Route value=" + (AnsiString)a + " Caller=" +
19037  (AnsiString)Caller);
19038  }
19039  if(((RouteElementPair.first != (int)a) || (RouteElementPair.second != b)) && ((SecondPair.first != (int)a) || (SecondPair.second != b)))
19040  // need one of pairs to match both RouteNumber and RouteElementNumber or fails
19041  {
19042  throw Exception("CheckMapAndRoutes Error - PrefDirVectorNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
19043  (AnsiString)CheckElement.VLoc + " 1st Map value RouteNum/ElementNum =" + (AnsiString)RouteElementPair.first + "/" +
19044  (AnsiString)RouteElementPair.second + " 2nd Map value =" + (AnsiString)SecondPair.first + "/" + (AnsiString)SecondPair.second +
19045  " Route value=" + (AnsiString)a + "/" + (AnsiString)b + " Caller=" + (AnsiString)Caller);
19046  }
19047  }
19048  }
19049  unsigned int SizeVal = 0;
19050 
19051 // check map and sum of route sizes match
19052  for(unsigned int a = 0; a < AllRoutesSize(); a++)
19053  {
19054  SizeVal += GetFixedRouteAt(117, a).PrefDirSize();
19055  }
19056  if(SizeVal != Route2MultiMap.size())
19057  {
19058  throw Exception("CheckMapAndRoutes Error - Map Size=" + (AnsiString)Route2MultiMap.size() + " RouteSize=" + (AnsiString)SizeVal + " Caller=" +
19059  (AnsiString)Caller);
19060  }
19061  Utilities->CallLogPop(404);
19062  return;
19063 }
19064 
19065 // ---------------------------------------------------------------------------
19066 
19067 void TAllRoutes::DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
19068 /*
19069  After a route has been erased from AllRoutesVector and its entries from Route2MultiMap, this
19070  function examines all the remaining entries in Route2MultiMap to see if their RouteNumbers
19071  exceed that for the erased route. Where this is so the RouteNumber is decremented.
19072 */
19073 {
19074  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteNumbersInRoute2MultiMap," + AnsiString(RouteNumber));
19075  if(!Route2MultiMap.empty())
19076  {
19077  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
19078  {
19079  if(Route2MultiMapIterator->second.first > RouteNumber)
19080  {
19081  Route2MultiMapIterator->second.first--;
19082  }
19083  }
19084  }
19085  Utilities->CallLogPop(405);
19086 }
19087 
19088 // ---------------------------------------------------------------------------
19089 
19090 void TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
19091 /*
19092  After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap, this
19093  function examines all the remaining entries in Route2MultiMap with the same RouteNumber as that
19094  for the erased element. Where a RouteElementNumber exceeds that for the erased element it is decremented.
19095 */
19096 {
19097  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteElementNumbersInRoute2MultiMap," +
19098  AnsiString(RouteNumber) + "," + AnsiString(ErasedElementNumber));
19099  if(!Route2MultiMap.empty())
19100  {
19101  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
19102  {
19103  if((Route2MultiMapIterator->second.first == RouteNumber) && (Route2MultiMapIterator->second.second > ErasedElementNumber))
19104  {
19105  Route2MultiMapIterator->second.second--;
19106  }
19107  }
19108  }
19109  Utilities->CallLogPop(406);
19110 }
19111 
19112 // ---------------------------------------------------------------------------
19113 
19114 void TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
19115 /*
19116  Erases the route element from Route2MultiMap and from the PrefDirVector.
19117  If there are no elements left in the PrefDirVector the route is cleared from AllRoutesVector. Route element numbers in the map are
19118  decremented if they are greater than the element number removed, and if the entire route is removed
19119  then the route numbers are also decremented in the map for route numbers that are greater than the route
19120  number that is removed.
19121 */
19122 {
19123  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RemoveRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
19124  AnsiString(ELink));
19125  TRouteElementPair RequiredRoutePair; // RouteNumber & RouteElementNumber
19126  TRoute2MultiMapIterator Route2MultiMapIterator;
19127 
19128  RequiredRoutePair = FindRoutePairFromRoute2MultiMap(0, HLoc, VLoc, ELink, Route2MultiMapIterator);
19129  if(RequiredRoutePair.first == -1)
19130  {
19131  throw Exception("Failed to find route element in RemoveRouteElement");
19132  }
19133  Route2MultiMap.erase(Route2MultiMapIterator);
19134  DecrementRouteElementNumbersInRoute2MultiMap(0, RequiredRoutePair.first, RequiredRoutePair.second);
19135 
19136 // even though element has been erased from the routemap, RequiredRoutePair still contains the element values
19137  TPrefDirElement LockedRouteElement, PrefDirElement = GetFixedRouteAt(118, RequiredRoutePair.first).GetFixedPrefDirElementAt(137, RequiredRoutePair.second);
19138 
19139  if(Track->TrackElementAt(157, PrefDirElement.TrackVectorPosition).Config[PrefDirElement.XLinkPos] == Signal)
19140  {
19141  Track->TrackElementAt(158, PrefDirElement.TrackVectorPosition).Attribute = 0; // change forward signals back to red
19142  }
19143 // don't need the section below (a) because when a train removes elements from the front of a locked route, there is a test in
19144 // ApproachLocking to determine whether the element immediately nearer the start of the route to the element being removed is still
19145 // present, and of not the element removal stops; and (b) because it never worked anyway! - IsElementInLockedRoute.... uses Route2MultiMap
19146 // to check if a route element is present, and the element has already been removed from the map - see above.
19147 
19148 // before erase the element check if it's in a locked route, and if so change the TruncateTrackVectorPosition to the next valid (XLinkPos] element position
19149 /*
19150  int LockedVectorNumber = -1;
19151  if(IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(5, PrefDirElement.TrackVectorPosition, PrefDirElement.XLinkPos, LockedRouteElement, LockedVectorNumber))
19152  {
19153  LockedRouteVector.at(LockedVectorNumber).TruncateTrackVectorPosition = PrefDirElement.Conn[PrefDirElement.XLinkPos];
19154  }
19155 */
19156 
19157 // erase element from route
19158  GetModifiableRouteAt(8, RequiredRoutePair.first).EraseRouteElementAt(&(GetModifiableRouteAt(9, RequiredRoutePair.first).GetModifiablePrefDirElementAt(1,
19159  RequiredRoutePair.second)));
19160 // CheckMapAndRoutes();//test - drop - tested below
19161 
19162 // remove ContinuationAutoSig route if element is in one since if any part of it is truncated the continuation exit will be removed - must
19163 // be so as continuation exit is at the end of the route, and truncation is from the end
19165  {
19167  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
19168  AutoSigVectorIT--)
19169  {
19170  if(AutoSigVectorIT->RouteNumber == RequiredRoutePair.first)
19171  {
19172  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT);
19173  }
19174  }
19175  }
19176 // now if last element from a route was removed need to remove the route from the route vector and from the LockedRouteVector if exists,
19177 // and adjust all the corresponding route numbers
19178  if(GetModifiableRouteAt(10, RequiredRoutePair.first).PrefDirSize() == 0)
19179  {
19180  TrainController->LogEvent("RouteRemoved," + AnsiString(GetFixedRouteAt(189, RequiredRoutePair.first).RouteID));
19181  AllRoutesVector.erase(AllRoutesVector.begin() + RequiredRoutePair.first);
19182  DecrementRouteNumbersInRoute2MultiMap(0, RequiredRoutePair.first);
19183 
19184 /* drop this: LockedVectorNumber was supposed to be determined from the above section that has been dropped, so this doesn't work
19185  It isn't needed anyway as a check is made after the Locked route timeout as to whether the end element is in a route or not, and if not
19186  it is erased then - see TInterface::ApproachLocking
19187 
19188  if(LockedVectorNumber > -1)
19189  {
19190  LockedRouteVector.erase(LockedRouteVector.begin() + LockedVectorNumber);
19191  }
19192 */
19193  // decrement route numbers in the locked route vector whether or not this route is a locked route
19194  if(!LockedRouteVector.empty())
19195  {
19196  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
19197  {
19198  if(LRVIT->RouteNumber > RequiredRoutePair.first)
19199  {
19200  LRVIT->RouteNumber--;
19201  }
19202  }
19203  }
19205  {
19207  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
19208  AutoSigVectorIT--)
19209  {
19210  if(AutoSigVectorIT->RouteNumber > RequiredRoutePair.first)
19211  {
19212  AutoSigVectorIT->RouteNumber--;
19213  }
19214  }
19215  }
19216  }
19217  CheckMapAndRoutes(7); // test
19218  Utilities->CallLogPop(407);
19219 }
19220 
19221 // ---------------------------------------------------------------------------
19222 
19223 void TAllRoutes::AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
19224 /*
19225  A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2MultiMap.
19226  Called from TAllRoutes::StoreOneRoute. Note that the IsARoute boolean variable is set in StoreRouteElementInPrefDirVector
19227  since that catches all route elements wherever created
19228 */
19229 {
19230  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
19231  AnsiString(ELink) + "," + AnsiString(RouteNumber) + "," + RouteElement.LogPrefDir());
19232  GetModifiableRouteAt(11, RouteNumber).StoreRouteElementInPrefDirVector(RouteElement);
19233  Route2MultiMapInsert(0, HLoc, VLoc, ELink, RouteNumber, GetModifiableRouteAt(12, RouteNumber).PrefDirSize() - 1);
19234  Utilities->CallLogPop(408);
19235 }
19236 
19237 // ---------------------------------------------------------------------------
19238 
19239 void TAllRoutes::SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
19240 /*
19241  Enter with signal at TrackVectorElement already set to red by the passing train.
19242  Identify the route that the TrackVectorPosition is in, carry out validity checks, then call SetAllRearwardsSignals to set signals
19243  in this route and all linked rearwards routes, unless find a train (a) in the current route, in which case the signals behind it are
19244  set (and behind any other trains in the current route), but only within the current route; or (b) in a linked rear route, in which
19245  case the function sets no further signals.
19246 */
19247 {
19248  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnAutoSigsRoute," + AnsiString(TrackVectorPosition) +
19249  "," + AnsiString(XLinkPos));
19250  TRouteElementPair RouteElementPair, SecondPair, RequiredPair;
19251  TTrackElement TE = Track->TrackElementAt(159, TrackVectorPosition);
19252 
19253  RouteElementPair = GetRouteElementDataFromRoute2MultiMap(9, TE.HLoc, TE.VLoc, SecondPair);
19254  if(RouteElementPair.first == -1)
19255  {
19256  throw Exception("Error, failed to find element in SetTrailingSignalsOnAutoSigsRoute - 1");
19257  }
19258  TPrefDirElement RouteElement = GetFixedRouteAt(119, RouteElementPair.first).GetFixedPrefDirElementAt(138, RouteElementPair.second);
19259 
19260  RequiredPair = RouteElementPair;
19261  if(RouteElement.XLinkPos != XLinkPos)
19262  {
19263  if(SecondPair.first != -1)
19264  {
19265  RouteElement = GetFixedRouteAt(120, SecondPair.first).GetFixedPrefDirElementAt(139, SecondPair.second);
19266  RequiredPair = SecondPair;
19267  if(RouteElement.XLinkPos != XLinkPos)
19268  {
19269  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 2");
19270  }
19271  }
19272  else
19273  {
19274  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 3");
19275  }
19276  }
19277 // new function
19278  SetAllRearwardsSignals(5, 0, RequiredPair.first, RequiredPair.second);
19279  Utilities->CallLogPop(409);
19280 }
19281 
19282 // ---------------------------------------------------------------------------
19283 
19284 void TAllRoutes::SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
19285 /*
19286  This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in TrainController to set signals on
19287  the AutoSigsRoute to correspond to a train having exited the route at a continuation, and passing further signals (outside the simulated
19288  railway). Initially the last passed signal will be red, then at the first call it will change to yellow and earlier signals will change
19289  accordingly, then double yellow, then green. There are only 3 calls in all for any given route, and the AccessNumber changes from 0 to 1
19290  to 2 for successive calls.
19291  Initially Attribute is set to AccessNumber + 1 to correspond to the first signal attribute to be set, then a number of validity checks
19292  are carried out on RouteNumber. Then SetAllRearwardsSignals is called to set signals in this route and all linked rearwards routes,
19293  unless find a train (a) in the current route, in which case the signals behind it are set (and behind any other trains in the current
19294  route), but only within the current route; or (b) in a linked rear route, in which case the function sets no further signals.
19295 */
19296 {
19297  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnContinuationRoute," + AnsiString(RouteNumber) + "," +
19298  AnsiString(AccessNumber));
19299  TPrefDirElement RouteElement;
19300  int Attribute = AccessNumber + 1;
19301 // signal attributes: 0=red; 1=yellow; 2=double yellow; 3 = green
19302  int x = GetFixedRouteAt(121, RouteNumber).PrefDirSize() - 1;
19303 
19304  if(!(GetFixedRouteAt(122, RouteNumber).GetFixedPrefDirElementAt(140, x).AutoSignals))
19305  {
19306  throw Exception("Error - route not AutoSignals in SetTrailingSignalsOnContinuationRoute");
19307  }
19308  if(GetFixedRouteAt(123, RouteNumber).GetFixedPrefDirElementAt(141, x).TrackType != Continuation)
19309  {
19310  throw Exception("Error - end element not continuation in SetTrailingSignalsOnContinuationRoute");
19311  }
19312  if(GetFixedRouteAt(124, RouteNumber).GetFixedPrefDirElementAt(142, x).Config[GetFixedRouteAt(125, RouteNumber).GetFixedPrefDirElementAt(143,
19313  x).XLinkPos] != End)
19314  {
19315  throw Exception("Error - end element a continuation in SetTrailingSignalsOnContinuationRoute but End not facing right way");
19316  }
19317 // new function
19318  SetAllRearwardsSignals(6, Attribute, RouteNumber, GetFixedRouteAt(126, RouteNumber).PrefDirSize() - 1);
19319  Utilities->CallLogPop(410);
19320 }
19321 
19322 // ---------------------------------------------------------------------------
19323 
19324 void TAllRoutes::SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
19325 /*
19326  Sets signals in all linked rearwards routes from the RouteStartPosition in RouteNumber, unless find a train (a) in the current route,
19327  in which case the signals behind it are set (and behind any other trains in the current route), but only within the current route;
19328  or (b) in a linked rear route, in which case the function sets no further signals.
19329 
19330  First call SetRearwardsSignalsReturnFalseForTrain (which is only called by this function) to set signals in route RouteNumber according
19331  to the received or modified (because of the forward look for buffers or continuation) Attribute. If no train is found during this call
19332  (returns true) then check for and call SetRearwardsSignalsReturnFalseForTrain for each rearwards linked route until either reach the
19333  beginning of the last linked route or find a train on a linked rear route. If no train was found during the RouteNumber call to
19334  SetRearwardsSignalsReturnFalseForTrain then the function terminates here.
19335  However if a train was found during the RouteNumber call to SetRearwardsSignalsReturnFalseForTrain then need to continue after the
19336  train in case had just added a route segment behind a train that now forms part of a single continuous route, otherwise the signals
19337  won't be set behind the train. First the route is examined element by element from the RouteStartPosition towards the start of the
19338  route until the train is found. Then the route elements are examined from the TrainPosition towards the start of the route until the
19339  first element behind the train is found. A recursive call to this function is then made from this behind-train position, to set all
19340  signals behind the train (and behind as many trains as there are on the single route) beginning with a red signal for the first signal
19341  found behind the train.
19342 
19343  Description of SetRearwardsSignalsReturnFalseForTrain for reference:
19344  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
19345  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
19346  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
19347  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
19348  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
19349  a route.
19350 
19351  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
19352  signal. If find a signal set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
19353  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3 [addition at v2.9.2: if signal or element beyond
19354  it is in a locked route then set signal to red & change Attribute to 0 - this fault reported by Simon Banham 21/07/21 as an image]. and continue working backwards
19355  for the next signal (or train - return false as before) and so on. On completion Attribute is passed back from the function as a
19356  reference. If no train is found before the beginning of the route is reached the function returns true
19357 
19358 */
19359 {
19360  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllRearwardsSignals," + AnsiString(Attribute) + "," +
19361  AnsiString(RouteNumber) + "," + AnsiString(RouteStartPosition));
19362  TPrefDirElement FirstElement = GetFixedRouteAt(127, RouteNumber).GetFixedPrefDirElementAt(144, 0);
19363  int RearwardLinkedRouteNumber;
19364 
19365  Track->LCFoundInRouteBuildingFlag = false; // only examined for the new route segment, not for linked routes
19366  if(GetFixedRouteAt(128, RouteNumber).SetRearwardsSignalsReturnFalseForTrain(1, Attribute, RouteStartPosition)) // updates Attribute to 1+ final
19367  // signal value in the route for use in further linked routes
19368  {
19369  if(FirstElement.Conn[FirstElement.ELinkPos] > -1) // GetRouteTypeAndNumber tests for this but check here to avoid call if == -1
19370  {
19371  while(GetRouteTypeAndNumber(6, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
19372  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
19373  {
19374  if(!(GetFixedRouteAt(129, RearwardLinkedRouteNumber).SetRearwardsSignalsReturnFalseForTrain(2, Attribute, AllRoutes->GetFixedRouteAt(130,
19375  RearwardLinkedRouteNumber).PrefDirSize() - 1)))
19376  {
19377  break;
19378  }
19379  // in above the RouteSettingFlag is set to false because this call is for routes that lie behind the route that is being set so don't want to
19380  // flash LCs on those routes
19381  FirstElement = AllRoutes->GetFixedRouteAt(131, RearwardLinkedRouteNumber).GetFixedPrefDirElementAt(145, 0);
19382  }
19383  }
19384  }
19385  else
19386  // found a train in the entry route before the beginning of the route, so need to continue after the train in case had just added a
19387  // route segment behind a train that now forms part of a single continuous route, otherwise the signals won't be set behind the train
19388  {
19389  int TrainID, TrainPosition, BehindTrainPosition;
19390  bool FoundTrain = false, BehindTrain = false;
19391  for(int x = RouteStartPosition; x >= 0; x--) // first step back from start position until find the train....
19392  {
19393  TPrefDirElement PrefDirElement = GetFixedRouteAt(132, RouteNumber).GetFixedPrefDirElementAt(146, x);
19394  TTrackElement TrackElement = Track->TrackElementAt(160, PrefDirElement.TrackVectorPosition);
19395  TrainID = TrackElement.TrainIDOnElement;
19396  if(TrackElement.TrackType == Bridge)
19397  {
19398  if(PrefDirElement.XLinkPos < 2)
19399  {
19400  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
19401  }
19402  else
19403  {
19404  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
19405  }
19406  }
19407  if(TrainID == -1)
19408  {
19409  continue;
19410  }
19411  else
19412  {
19413  FoundTrain = true;
19414  TrainPosition = x;
19415  break;
19416  }
19417  }
19418  if(FoundTrain && (TrainPosition > 1)) // if TrainPosition 1 or less then no route behind the train so can stop
19419  {
19420  for(int x = TrainPosition; x >= 0; x--) // then step back from that position until find element behind the train - ignore any
19421  {
19422  // signals that the train itself is straddling, need the first signal behind the train to be set to red, when the train passes
19423  // the signal it's straddling the rearwards signals will be reset again. Even if there are two or more trains adjacent still
19424  // need the element behind the rearmost train.
19425  TPrefDirElement PrefDirElement = GetFixedRouteAt(133, RouteNumber).GetFixedPrefDirElementAt(147, x);
19426  TTrackElement TrackElement = Track->TrackElementAt(161, PrefDirElement.TrackVectorPosition);
19427  TrainID = TrackElement.TrainIDOnElement;
19428  if(TrackElement.TrackType == Bridge)
19429  {
19430  if(PrefDirElement.XLinkPos < 2)
19431  {
19432  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
19433  }
19434  else
19435  {
19436  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
19437  }
19438  }
19439  if(TrainID != -1)
19440  {
19441  continue; // still on train
19442  }
19443  else
19444  {
19445  BehindTrain = true;
19446  BehindTrainPosition = x;
19447  break;
19448  }
19449  }
19450  if(BehindTrain) // then carry out a recursive rearward signal setting behind the train &
19451  // so on for as many trains as there are on the single route
19452  {
19453  SetAllRearwardsSignals(7, 0, RouteNumber, BehindTrainPosition); // false because can't set a route where there is a train
19454  // first signal behind train to be red
19455  }
19456  }
19457  }
19458  Utilities->CallLogPop(411);
19459 }
19460 
19461 // ---------------------------------------------------------------------------
19462 
19463 bool TAllRoutes::RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
19464 {
19465 /* Locked if a train moving in the direction of the route within 3 signals back from truncate point (on the route itself or any linked routes, or on the element
19466  immediately before the start of the route or linked route - this because train cancels route elements that it touches) unless
19467  first signal is red, then OK
19468 */
19469  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteLockingRequired," + AnsiString(RouteNumber) + "," +
19470  AnsiString(RouteTruncatePosition));
19471  int SignalCount = 0, TrainID, RearwardLinkedRouteNumber, StartPosition = RouteTruncatePosition;
19472  TOneRoute CurrentRoute = GetFixedRouteAt(134, RouteNumber);
19473  TPrefDirElement PrefDirElement, FirstElement;
19474  TTrackElement TrackElement;
19475  bool ExamineRoute = true;
19476 
19477  while(ExamineRoute)
19478  {
19479  for(int x = StartPosition; x >= 0; x--) //work back along the route from the truncate point
19480  {
19481  PrefDirElement = CurrentRoute.GetFixedPrefDirElementAt(148, x);
19482  TrackElement = Track->TrackElementAt(162, PrefDirElement.TrackVectorPosition);
19483  TrainID = TrackElement.TrainIDOnElement;
19484  if(TrackElement.TrackType == Bridge)
19485  {
19486  if(PrefDirElement.XLinkPos < 2)
19487  {
19488  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
19489  }
19490  else
19491  {
19492  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
19493  }
19494  }
19495  if(TrainID > -1)
19496  {
19497  if(TrainController->TrainVectorAtIdent(36, TrainID).Stopped())
19498  {
19499  //any trains further back in route will be protected by the red signal behind the stopped train
19500  Utilities->CallLogPop(412);
19501  return(false);
19502  }
19503  //added at v2.4.2 for trains facing the wrong way & moving but haven't moved a half element yet so route still intact
19504  if(TrainController->TrainVectorAtIdent(49, TrainID).GetLeadElement() != PrefDirElement.TrackVectorPosition) //if it isn't then the train is facing the
19505  //other way & can cancel the route
19506  {
19507  Utilities->CallLogPop(2203);
19508  return(false);
19509  }
19510  Utilities->CallLogPop(1961); //otherwise need to lock the route as have found a train on the route (trains forward of the truncate point caught by
19511  return(true); //TrainOccupyingRoute which is outside this function but also causes route locking)
19512  }
19513  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal) // XLinkPos because signal has to be facing same direction as PrefDir to count
19514  {
19515  if(TrackElement.Attribute == 0)
19516  {
19517  Utilities->CallLogPop(413);
19518  return(false); // OK, red signal in front of a train
19519  }
19520  SignalCount++;
19521  if(SignalCount >= 3)
19522  {
19523  Utilities->CallLogPop(414);
19524  return(false);
19525  }
19526  }
19527  if(PrefDirElement.Config[PrefDirElement.ELinkPos] == End) // buffer or continuation & no train
19528  // ElinkPos because working back along PrefDir to beginning
19529  {
19530  Utilities->CallLogPop(415);
19531  return(false); // test - set to true to create a locked buffer-ended route, false for normal use
19532  }
19533  }
19534  //now look at linked rearwards routes
19535  FirstElement = CurrentRoute.GetFixedPrefDirElementAt(149, 0);
19536  StartPosition = CurrentRoute.PrefDirSize() - 1;
19537  if(GetRouteTypeAndNumber(7, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
19538  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
19539  {
19540  CurrentRoute = GetFixedRouteAt(135, RearwardLinkedRouteNumber);
19541  ExamineRoute = true;
19542  StartPosition = GetFixedRouteAt(136, RearwardLinkedRouteNumber).PrefDirSize() - 1;
19543  }
19544  else
19545  {
19546  // here check for a train on the element immediately before the first route element
19547  TTrackElement PriorTrackElement = Track->TrackElementAt(489, FirstElement.Conn[FirstElement.ELinkPos]);
19548  TrainID = PriorTrackElement.TrainIDOnElement;
19549  if(PriorTrackElement.TrackType == Bridge)
19550  {
19551  if(FirstElement.ConnLinkPos[FirstElement.ELinkPos] < 2)
19552  {
19553  TrainID = PriorTrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
19554  }
19555  else
19556  {
19557  TrainID = PriorTrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
19558  }
19559  }
19560  if(TrainID > -1)
19561  {
19562  if(TrainController->TrainVectorAtIdent(37, TrainID).Stopped())
19563  {
19564  Utilities->CallLogPop(748);
19565  return(false);
19566  }
19567  //added at v2.4.2 for trains facing the wrong way on the prior element & moving but haven't moved a half element yet
19568  if(TrainController->TrainVectorAtIdent(50, TrainID).GetLeadElement() != FirstElement.Conn[FirstElement.ELinkPos]) //if it isn't then the train is facing the
19569  //other way & can cancel the route
19570  {
19571  Utilities->CallLogPop(2204);
19572  return(false);
19573  }
19574  Utilities->CallLogPop(1962);
19575  return(true); //otherwise need to lock the route
19576  }
19577  ExamineRoute = false;
19578  }
19579  }
19580 // if reach beginning of all rear routes without finding a train and there aren't 3 signals then truncate the route
19581 // as trains running on unrouted lines are already at risk of wrong points etc so no benefit locking the route
19582  Utilities->CallLogPop(416);
19583  return(false);
19584 }
19585 
19586 // ---------------------------------------------------------------------------
19587 
19588 bool TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos,
19589  TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
19590 {
19591  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber," +
19592  AnsiString(TrackVectorPosition) + "," + AnsiString(XLinkPos));
19593  TPrefDirElement InternalPrefDirElement; // blank element
19594 
19595  PrefDirElement = InternalPrefDirElement;
19596  if(LockedRouteVector.empty())
19597  {
19598  Utilities->CallLogPop(417);
19599  return(false);
19600  }
19601 // make sure at least one locked route record is still valid - train may have removed it, if last element still present locked route still exists,
19602 // even if some elements have been removed from the front by a train
19603  bool InLockedRoute = false;
19604 
19605  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
19606  {
19607  if(TrackIsInARoute(14, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
19608  {
19609  // end of route can't be points, crossover or bridge so danger of route being on the other track of a 2-track element
19610  // doesn't arise)
19611  InLockedRoute = true;
19612  break;
19613  }
19614  }
19615  if(!InLockedRoute)
19616  {
19617  Utilities->CallLogPop(418);
19618  return(false);
19619  }
19620  int RouteNumber, VectorCount = 0;
19621  TRouteType RouteType;
19622 
19623  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
19624  {
19625  RouteType = GetRouteTypeAndNumber(8, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos, RouteNumber);
19626  if(RouteType == NoRoute)
19627  {
19628  continue;
19629  }
19630  if((GetFixedRouteAt(137, RouteNumber).GetFixedPrefDirElementAt(150, GetFixedRouteAt(138, RouteNumber).PrefDirSize() - 1).TrackVectorPosition != (int)
19631  LRVIT->LastTrackVectorPosition) || (GetFixedRouteAt(139, RouteNumber).GetFixedPrefDirElementAt(151,
19632  GetFixedRouteAt(140, RouteNumber).PrefDirSize() - 1).XLinkPos != LRVIT->LastXLinkPos))
19633  {
19634  throw Exception
19635  ("Error, last element in locked route doesn't correspond with last element in associated route in IsElementInLockedRouteGetPrefDirElement");
19636  }
19637  for(int x = GetFixedRouteAt(141, RouteNumber).PrefDirSize() - 1; x >= 0; x--)
19638  {
19639  InternalPrefDirElement = GetFixedRouteAt(142, RouteNumber).GetFixedPrefDirElementAt(152, x);
19640  if(InternalPrefDirElement.TrackVectorPosition != (int)LRVIT->TruncateTrackVectorPosition)
19641  {
19642  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
19643  {
19644  PrefDirElement = InternalPrefDirElement;
19645  LockedVectorNumber = VectorCount;
19646  Utilities->CallLogPop(419);
19647  return(true);
19648  }
19649  }
19650  else if(InternalPrefDirElement.TrackVectorPosition == (int)LRVIT->TruncateTrackVectorPosition)
19651  {
19652  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
19653  {
19654  PrefDirElement = InternalPrefDirElement;
19655  LockedVectorNumber = VectorCount;
19656  Utilities->CallLogPop(420);
19657  return(true);
19658  }
19659  else
19660  {
19661  break; // reached & tested LRVIT->TruncateTrackVectorPosition for a match so don't want to go any further for this route
19662  }
19663  }
19664  }
19665  VectorCount++;
19666  }
19667  Utilities->CallLogPop(421);
19668  return(false);
19669 }
19670 
19671 // ---------------------------------------------------------------------------
19672 
19674 {
19675  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteVectorNumber," + AnsiString(RouteID.GetInt()));
19676  for(unsigned int x = 0; x < AllRoutesSize(); x++)
19677  {
19678  if(GetFixedRouteAt(157, x).RouteID == RouteID.GetInt())
19679  {
19680  Utilities->CallLogPop(963);
19681  return(x);
19682  }
19683  }
19684  throw Exception("Error, failed to find RouteID in GetRouteVectorNumber for ID: " + AnsiString(RouteID.GetInt()));
19685 }
19686 
19687 // ---------------------------------------------------------------------------
19688 
19690 // added at v1.3.1 after an error was generated when operating Ian Walker's Chiltern Railway
19691 // found to be due to a route having been removed by a train moving in the wrong direction after the route was selected but before it completed (i.e. route removed while flashing)
19692 {
19693  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsThereARouteAtIDNumber," + AnsiString(RouteID.GetInt()));
19694  for(unsigned int x = 0; x < AllRoutesSize(); x++)
19695  {
19696  if(GetFixedRouteAt(45, x).RouteID == RouteID.GetInt())
19697  {
19698  Utilities->CallLogPop(2039);
19699  return(true);
19700  }
19701  }
19702  Utilities->CallLogPop(2040);
19703  return(false);
19704 }
19705 
19706 // ---------------------------------------------------------------------------
19707 
19709 {
19710  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAtIDNumber," + AnsiString(RouteID.GetInt()));
19711  for(unsigned int x = 0; x < AllRoutesSize(); x++)
19712  {
19713  if(GetFixedRouteAt(163, x).RouteID == RouteID.GetInt())
19714  {
19715  Utilities->CallLogPop(964);
19716  return(GetFixedRouteAt(159, x));
19717  }
19718  }
19719  throw Exception("Error, failed to find RouteID in GetFixedRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
19720 }
19721 
19722 // ---------------------------------------------------------------------------
19723 
19725 {
19726  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteATIDNumber," + AnsiString(RouteID.GetInt()));
19727  for(unsigned int x = 0; x < AllRoutesSize(); x++)
19728  {
19729  if(GetFixedRouteAt(164, x).RouteID == RouteID.GetInt())
19730  {
19731  Utilities->CallLogPop(965);
19732  return(GetModifiableRouteAt(15, x));
19733  }
19734  }
19735  throw Exception("Error, failed to find RouteID in GetModifiableRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
19736 }
19737 
19738 // ---------------------------------------------------------------------------
19739 
19740 void TAllRoutes::SaveRoutes(int Caller, std::ofstream &OutFile)
19741 {
19742  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveRoutes");
19743  Utilities->SaveFileInt(OutFile, AllRoutesSize()); // so know how many to reload
19744  Utilities->SaveFileInt(OutFile, NextRouteID);
19745  for(unsigned int x = 0; x < AllRoutesSize(); x++)
19746  {
19747  TOneRoute OneRoute = GetFixedRouteAt(165, x);
19748  Utilities->SaveFileInt(OutFile, OneRoute.RouteID);
19749  OneRoute.SavePrefDirVector(6, OutFile);
19750  }
19751  Utilities->CallLogPop(1442);
19752 }
19753 
19754 // ---------------------------------------------------------------------------
19755 
19756 bool TAllRoutes::LoadRoutes(int Caller, std::ifstream &InFile)
19757 {
19758  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRoutes");
19759  int NumberOfRoutes;
19760 
19761  NumberOfRoutes = Utilities->LoadFileInt(InFile);
19762  NextRouteID = Utilities->LoadFileInt(InFile);
19763  for(int x = 0; x < NumberOfRoutes; x++)
19764  {
19765  TOneRoute OneRoute; // empty route
19766  OneRoute.RouteID = Utilities->LoadFileInt(InFile);
19767  OneRoute.LoadPrefDir(2, InFile);
19769  {
19770  StoreOneRouteAfterSessionLoad(0, &OneRoute);
19771  }
19772  else
19773  {
19774  Utilities->CallLogPop(1443);
19775  return(false);
19776  }
19777  }
19778  Utilities->CallLogPop(1444);
19779  return(true);
19780 }
19781 
19782 // ---------------------------------------------------------------------------
19783 bool TAllRoutes::CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
19784 {
19785  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckRoutes," + AnsiString(NumberOfActiveElements));
19786  int NumberOfRoutes = Utilities->LoadFileInt(InFile);
19787 
19788  if((NumberOfRoutes < 0) || (NumberOfRoutes > 5000))
19789  {
19790  Utilities->CallLogPop(1445);
19791  return(false);
19792  }
19793  int NextID = Utilities->LoadFileInt(InFile);
19794 
19795  if((NextID < 0) || (NextID > 1000000))
19796  {
19797  Utilities->CallLogPop(1446);
19798  return(false);
19799  }
19800  for(int x = 0; x < NumberOfRoutes; x++)
19801  {
19802  int RouteID = Utilities->LoadFileInt(InFile);
19803  if((RouteID < 0) || (RouteID > 20000))
19804  {
19805  Utilities->CallLogPop(1447);
19806  return(false);
19807  }
19808  TOneRoute OneRoute; // create an empty route so CheckOnePrefDir can be called
19809  if(!(OneRoute.CheckOnePrefDir(3, NumberOfActiveElements, InFile)))
19810  {
19811  Utilities->CallLogPop(1448);
19812  return(false);
19813  }
19814  }
19815  Utilities->CallLogPop(1449);
19816  return(true);
19817 }
19818 
19819 // ---------------------------------------------------------------------------
19820 
19821 bool TAllRoutes::CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
19822 {
19823  // return true for a loop
19824  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckForLoopingRoute," + AnsiString(EndPosition) + "," +
19825  AnsiString(StartPosition));
19826  if(EndPosition == StartPosition)
19827  {
19828  Utilities->CallLogPop(1839);
19829  return(true); // shouldn't happen but treat as a loop if does
19830  }
19831 // begin at EndPosition & EndXLinkPos & work forwards until reach end of route (return false) or StartElement (return true)
19832  int TVPos = EndPosition; //TVPos is the current element and NewTVPos is the element it connects to
19833  int LkPos = EndXLinkPos; //LkPos is the exit link and NewLkPos is the entry link of the linked element
19834 
19835  while(TrackIsInARoute(15, TVPos, LkPos))
19836  {
19837  int NewTVPos = Track->TrackElementAt(826, TVPos).Conn[LkPos]; //see above
19838  int NewLkPos = -1;
19839  if(NewTVPos > -1)
19840  {
19841  NewLkPos = Track->TrackElementAt(827, TVPos).ConnLinkPos[LkPos]; // this is the entry link pos
19842  if(NewLkPos == -1)
19843  {
19844  Utilities->CallLogPop(1840);
19845  return(true); // shouldn't arise but treat as loop if does
19846  }
19847  }
19848  else // reached a buffer or continuation
19849  {
19850  Utilities->CallLogPop(1841);
19851  return(false);
19852  }
19853 //Error found by Xeon notified by email 13/10/20.
19854 //Need to make sure there is a route with the new entry link NewLkPos on the next element (TrackIsInARoute normally used where it doesn't matter which track a route
19855 //is on - except for bridges). But here a route can end at a trailing point leg or a crossover and if so it doesn't link to the route on the other track, and needs to
19856 //return false. Without the new check below the program gets stuck in an endless loop, which is the error that Xeon found.
19857 //If there isn't a route at all on the next element then it would return false at the next iteration so can return false here.
19858 //New check added for v2.6.0
19859 //Note: Could probably use GetRouteTypeAndNumber in place of TrackIsInARoute in the while statement above and dispense with this new check, but I prefer to keep mods as simple
19860 //as possible in case there are other unforeseen effects.
19861  int RouteNumber; //dummy, not used
19862  if(GetRouteTypeAndNumber(36, NewTVPos, NewLkPos, RouteNumber) == NoRoute)
19863  {
19864  Utilities->CallLogPop(2241);
19865  return(false);
19866  }
19867  //now make the connected element the current element, read across the TV number and determine the exit link
19868  TVPos = NewTVPos;
19869  if(Track->TrackElementAt(828, TVPos).TrackType == Points)
19870  {
19871  if((NewLkPos == 0) || (NewLkPos == 2)) // leading points
19872  {
19873  if(Track->TrackElementAt(829, TVPos).Attribute == 0)
19874  {
19875  LkPos = 1;
19876  }
19877  else
19878  {
19879  LkPos = 3;
19880  }
19881  }
19882  else
19883  {
19884  LkPos = 0;
19885  }
19886  }
19887  else
19888  {
19889  LkPos = Track->GetNonPointsOppositeLinkPos(NewLkPos);
19890  }
19891  if(TVPos == StartPosition)
19892  {
19893  Utilities->CallLogPop(1842);
19894  return(true); // it is a loop
19895  }
19896  }
19897  Utilities->CallLogPop(1843);
19898  return(false); // reached end of route so not a loop
19899 }
19900 
19901 // ---------------------------------------------------------------------------
19902 
19903 bool TAllRoutes::DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
19904 /*
19905  Track geometry allows diagonals to cross without occupying the same track element, so when
19906  route plotting it is necessary to check if there is an existing route or a train on such a crossing
19907  diagonal. Returns true for a fouled diagonal. Enter with H & V set for the element whose diagonal
19908  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
19909  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
19910  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
19911  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
19912  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
19913  Each of these is examined in turn for each route element in the relevant position.
19914 
19915  NOTE: Originally this failed to detect a train fouling a diagonal. v1.2.0 checks for a train present on a
19916  crossing diagonal element using a new bool function TTrack::TrainOnLink(int HLoc, int VLoc, int Link)
19917  that returns false in all cases (including elements & links not present) except train present.
19918 */
19919 {
19920  int TrainID; // not used in this function
19921 
19922  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRouteOrTrain," + AnsiString(HLoc) + "," +
19923  AnsiString(VLoc) + "," + AnsiString(DiagonalLinkNumber));
19924  TPrefDirElement TempPrefDirElement;
19925  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
19926 
19927  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(4, HLoc - 1, VLoc, SecondPair);
19928  if(FirstPair.first > -1)
19929  {
19930  TempPrefDirElement = AllRoutes->GetFixedRouteAt(50, FirstPair.first).GetFixedPrefDirElementAt(70, FirstPair.second);
19931  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19932  {
19933  Utilities->CallLogPop(310);
19934  return(true);
19935  }
19936  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19937  {
19938  Utilities->CallLogPop(311);
19939  return(true);
19940  }
19941  }
19942  if(SecondPair.first > -1)
19943  {
19944  TempPrefDirElement = AllRoutes->GetFixedRouteAt(51, SecondPair.first).GetFixedPrefDirElementAt(71, SecondPair.second);
19945  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19946  {
19947  Utilities->CallLogPop(312);
19948  return(true);
19949  }
19950  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19951  {
19952  Utilities->CallLogPop(313);
19953  return(true);
19954  }
19955  }
19956  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(0, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && Track->TrainOnLink(1, HLoc - 1, VLoc,
19957  9, TrainID)))
19958  {
19959  Utilities->CallLogPop(1997);
19960  return(true);
19961  }
19962  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(5, HLoc, VLoc - 1, SecondPair);
19963  if(FirstPair.first > -1)
19964  {
19965  TempPrefDirElement = AllRoutes->GetFixedRouteAt(52, FirstPair.first).GetFixedPrefDirElementAt(72, FirstPair.second);
19966  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19967  {
19968  Utilities->CallLogPop(314);
19969  return(true);
19970  }
19971  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19972  {
19973  Utilities->CallLogPop(315);
19974  return(true);
19975  }
19976  }
19977  if(SecondPair.first > -1)
19978  {
19979  TempPrefDirElement = AllRoutes->GetFixedRouteAt(53, SecondPair.first).GetFixedPrefDirElementAt(73, SecondPair.second);
19980  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19981  {
19982  Utilities->CallLogPop(316);
19983  return(true);
19984  }
19985  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19986  {
19987  Utilities->CallLogPop(317);
19988  return(true);
19989  }
19990  }
19991  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(2, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && Track->TrainOnLink(3, HLoc, VLoc - 1,
19992  9, TrainID)))
19993  {
19994  Utilities->CallLogPop(1998);
19995  return(true);
19996  }
19997  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(6, HLoc + 1, VLoc, SecondPair);
19998  if(FirstPair.first > -1)
19999  {
20000  TempPrefDirElement = AllRoutes->GetFixedRouteAt(54, FirstPair.first).GetFixedPrefDirElementAt(74, FirstPair.second);
20001  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20002  {
20003  Utilities->CallLogPop(318);
20004  return(true);
20005  }
20006  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20007  {
20008  Utilities->CallLogPop(319);
20009  return(true);
20010  }
20011  }
20012  if(SecondPair.first > -1)
20013  {
20014  TempPrefDirElement = AllRoutes->GetFixedRouteAt(55, SecondPair.first).GetFixedPrefDirElementAt(75, SecondPair.second);
20015  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20016  {
20017  Utilities->CallLogPop(320);
20018  return(true);
20019  }
20020  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20021  {
20022  Utilities->CallLogPop(321);
20023  return(true);
20024  }
20025  }
20026  if(((DiagonalLinkNumber == 3) && Track->TrainOnLink(4, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(5, HLoc + 1, VLoc,
20027  7, TrainID)))
20028  {
20029  Utilities->CallLogPop(1999);
20030  return(true);
20031  }
20032  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(7, HLoc, VLoc + 1, SecondPair);
20033  if(FirstPair.first > -1)
20034  {
20035  TempPrefDirElement = AllRoutes->GetFixedRouteAt(56, FirstPair.first).GetFixedPrefDirElementAt(76, FirstPair.second);
20036  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20037  {
20038  Utilities->CallLogPop(322);
20039  return(true);
20040  }
20041  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20042  {
20043  Utilities->CallLogPop(323);
20044  return(true);
20045  }
20046  }
20047  if(SecondPair.first > -1)
20048  {
20049  TempPrefDirElement = AllRoutes->GetFixedRouteAt(57, SecondPair.first).GetFixedPrefDirElementAt(77, SecondPair.second);
20050  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20051  {
20052  Utilities->CallLogPop(324);
20053  return(true);
20054  }
20055  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20056  {
20057  Utilities->CallLogPop(325);
20058  return(true);
20059  }
20060  }
20061  if(((DiagonalLinkNumber == 7) && Track->TrainOnLink(6, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(7, HLoc, VLoc + 1,
20062  3, TrainID)))
20063  {
20064  Utilities->CallLogPop(2000);
20065  return(true);
20066  }
20067  Utilities->CallLogPop(326);
20068  return(false);
20069 }
20070 
20071 // ---------------------------------------------------------------------------
20072 
20073 bool TAllRoutes::DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
20074 /*
20075  As above but checks for a route only (may or may not be a train). Enter with H & V set for the element whose diagonal
20076  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
20077  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
20078  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
20079  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
20080  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
20081  Each of these is examined in turn for each route element in the relevant position.
20082 */
20083 {
20084  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
20085  "," + AnsiString(DiagonalLinkNumber));
20086  TPrefDirElement TempPrefDirElement;
20087  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
20088 
20089  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(17, HLoc - 1, VLoc, SecondPair);
20090  if(FirstPair.first > -1)
20091  {
20092  TempPrefDirElement = AllRoutes->GetFixedRouteAt(197, FirstPair.first).GetFixedPrefDirElementAt(233, FirstPair.second);
20093  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20094  {
20095  Utilities->CallLogPop(2010);
20096  return(true);
20097  }
20098  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
20099  {
20100  Utilities->CallLogPop(2011);
20101  return(true);
20102  }
20103  }
20104  if(SecondPair.first > -1)
20105  {
20106  TempPrefDirElement = AllRoutes->GetFixedRouteAt(198, SecondPair.first).GetFixedPrefDirElementAt(234, SecondPair.second);
20107  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20108  {
20109  Utilities->CallLogPop(2012);
20110  return(true);
20111  }
20112  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
20113  {
20114  Utilities->CallLogPop(2013);
20115  return(true);
20116  }
20117  }
20118  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(18, HLoc, VLoc - 1, SecondPair);
20119  if(FirstPair.first > -1)
20120  {
20121  TempPrefDirElement = AllRoutes->GetFixedRouteAt(199, FirstPair.first).GetFixedPrefDirElementAt(235, FirstPair.second);
20122  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20123  {
20124  Utilities->CallLogPop(2014);
20125  return(true);
20126  }
20127  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
20128  {
20129  Utilities->CallLogPop(2015);
20130  return(true);
20131  }
20132  }
20133  if(SecondPair.first > -1)
20134  {
20135  TempPrefDirElement = AllRoutes->GetFixedRouteAt(200, SecondPair.first).GetFixedPrefDirElementAt(236, SecondPair.second);
20136  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20137  {
20138  Utilities->CallLogPop(2016);
20139  return(true);
20140  }
20141  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
20142  {
20143  Utilities->CallLogPop(2017);
20144  return(true);
20145  }
20146  }
20147  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(19, HLoc + 1, VLoc, SecondPair);
20148  if(FirstPair.first > -1)
20149  {
20150  TempPrefDirElement = AllRoutes->GetFixedRouteAt(201, FirstPair.first).GetFixedPrefDirElementAt(237, FirstPair.second);
20151  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20152  {
20153  Utilities->CallLogPop(2018);
20154  return(true);
20155  }
20156  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20157  {
20158  Utilities->CallLogPop(2019);
20159  return(true);
20160  }
20161  }
20162  if(SecondPair.first > -1)
20163  {
20164  TempPrefDirElement = AllRoutes->GetFixedRouteAt(202, SecondPair.first).GetFixedPrefDirElementAt(238, SecondPair.second);
20165  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20166  {
20167  Utilities->CallLogPop(2020);
20168  return(true);
20169  }
20170  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
20171  {
20172  Utilities->CallLogPop(2021);
20173  return(true);
20174  }
20175  }
20176  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(20, HLoc, VLoc + 1, SecondPair);
20177  if(FirstPair.first > -1)
20178  {
20179  TempPrefDirElement = AllRoutes->GetFixedRouteAt(203, FirstPair.first).GetFixedPrefDirElementAt(239, FirstPair.second);
20180  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20181  {
20182  Utilities->CallLogPop(2022);
20183  return(true);
20184  }
20185  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20186  {
20187  Utilities->CallLogPop(2023);
20188  return(true);
20189  }
20190  }
20191  if(SecondPair.first > -1)
20192  {
20193  TempPrefDirElement = AllRoutes->GetFixedRouteAt(204, SecondPair.first).GetFixedPrefDirElementAt(240, SecondPair.second);
20194  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
20195  {
20196  Utilities->CallLogPop(2024);
20197  return(true);
20198  }
20199  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
20200  {
20201  Utilities->CallLogPop(2025);
20202  return(true);
20203  }
20204  }
20205  Utilities->CallLogPop(2026);
20206  return(false);
20207 }
20208 
20209 // ---------------------------------------------------------------------------
20210 
20211 
TTrain::LinkOccupied
bool LinkOccupied(int Caller, int TrackVectorPosition, int LinkNumber)
Added at v1.2.0: true if any part of train on specific link, false otherwise, including no link prese...
Definition: TrainUnit.cpp:8983
TRailGraphics::gl70
Graphics::TBitmap * gl70
Definition: GraphicUnit.h:693
TRailGraphics::bm72CallingOn
Graphics::TBitmap * bm72CallingOn
Definition: GraphicUnit.h:478
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:18318
TPrefDirRoute
TPrefDirRoute
< used in TOnePrefDir::PrefDirMarker to indicate whether the function is being called for a preferred...
Definition: TrackUnit.h:1320
TRailGraphics::sm120
Graphics::TBitmap * sm120
Definition: GraphicUnit.h:950
TRailGraphics::bm7
Graphics::TBitmap * bm7
Definition: GraphicUnit.h:465
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:11604
TRailGraphics::gl58
Graphics::TBitmap * gl58
Definition: GraphicUnit.h:679
TRailGraphics::LCLHSVerMan
Graphics::TBitmap * LCLHSVerMan
Definition: GraphicUnit.h:746
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:36
TRailGraphics::gl145
Graphics::TBitmap * gl145
Definition: GraphicUnit.h:629
TRailGraphics::gl102
Graphics::TBitmap * gl102
Definition: GraphicUnit.h:581
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:11577
TGraphicElement::HPos
int HPos
Definition: TrackUnit.h:435
TTrack::GapVLoc
int GapVLoc
record gap setting info
Definition: TrackUnit.h:569
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:50
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:80
TRailGraphics::bm11
Graphics::TBitmap * bm11
Definition: GraphicUnit.h:354
TRailGraphics::sm99
Graphics::TBitmap * sm99
Definition: GraphicUnit.h:891
TTrack::ResetGapsFromGapMap
bool ResetGapsFromGapMap(int Caller)
Called by RepositionAndMapTrack to reset the connecting elements of all set gaps (their TrackVector p...
Definition: TrackUnit.cpp:5568
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:13122
TRailGraphics::sm129
Graphics::TBitmap * sm129
Definition: GraphicUnit.h:788
TFixedTrackPiece
Definition: TrackUnit.h:82
TFixedTrackPiece::PlotFixedTrackElement
void PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
Plot the element on the railway display at position HLocInput & VLocInput.
Definition: TrackUnit.cpp:128
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1731
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:190
TTrack::LNDone2MultiMap
TLNDone2MultiMap LNDone2MultiMap
multimap of processed location name elements (see type for more information above)
Definition: TrackUnit.h:814
TTextHandler::RebuildFromTextVector
void RebuildFromTextVector(int Caller, TDisplay *Disp)
display all text items in TextVector on the screen
Definition: TextUnit.cpp:425
TRailGraphics::sm72
Graphics::TBitmap * sm72
Definition: GraphicUnit.h:941
TAllRoutes::Route2MultiMapInsert
void Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
Insert an entry in Route2MultiMap. Called by TAllRoutes::AddRouteElement.
Definition: TrackUnit.cpp:18914
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:91
TRailGraphics::sm2
Graphics::TBitmap * sm2
Definition: GraphicUnit.h:807
clB5G0R0
#define clB5G0R0
Definition: GraphicUnit.h:246
TRailGraphics::sm73
Graphics::TBitmap * sm73
Definition: GraphicUnit.h:942
TTrack::IsNamedNonStationLocationPresent
bool IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location at HLoc & VLoc.
Definition: TrackUnit.cpp:10059
TRailGraphics::sm21
Graphics::TBitmap * sm21
Definition: GraphicUnit.h:809
TAllRoutes::SetAllRearwardsSignals
void SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
Set rearwards signals from the specified route starting position.
Definition: TrackUnit.cpp:19324
TRailGraphics::sm123
Graphics::TBitmap * sm123
Definition: GraphicUnit.h:953
TOnePrefDir::SearchLimitLowV
int SearchLimitLowV
Definition: TrackUnit.h:1374
TRailGraphics::bm8
Graphics::TBitmap * bm8
Definition: GraphicUnit.h:510
TTrack::GapMap
TGapMap GapMap
map of gaps (see type for more information above)
Definition: TrackUnit.h:806
TRailGraphics::gl117
Graphics::TBitmap * gl117
Definition: GraphicUnit.h:597
TRailGraphics::gl89set
Graphics::TBitmap * gl89set
Definition: GraphicUnit.h:718
TOnePrefDir::ErasePrefDirElementAt
void ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNum...
Definition: TrackUnit.cpp:13646
TRailGraphics::sm104
Graphics::TBitmap * sm104
Definition: GraphicUnit.h:775
TRailGraphics::gl19
Graphics::TBitmap * gl19
Definition: GraphicUnit.h:636
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:824
TGraphicElement::ScreenSourceSet
bool ScreenSourceSet
Definition: TrackUnit.h:433
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:13162
TRailGraphics::gl72
Graphics::TBitmap * gl72
Definition: GraphicUnit.h:695
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Definition: GraphicUnit.cpp:3780
TRailGraphics::gl88set
Graphics::TBitmap * gl88set
Definition: GraphicUnit.h:716
TRailGraphics::bm28
Graphics::TBitmap * bm28
Definition: GraphicUnit.h:396
PerfLogForm
TPerfLogForm * PerfLogForm
Definition: PerfLogUnit.cpp:11
TRailGraphics::bm68grounddblred
Graphics::TBitmap * bm68grounddblred
Definition: GraphicUnit.h:455
TRailGraphics::smLC
Graphics::TBitmap * smLC
Definition: GraphicUnit.h:897
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:804
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:284
TTrack::IsLCBarrierDownAtHV
bool IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc)
True if an open (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7305
TAllRoutes::TLockedRouteClass::TruncateTrackVectorPosition
unsigned int TruncateTrackVectorPosition
the TrackVector position of the element selected for truncation
Definition: TrackUnit.h:1648
TOneRoute::GetRouteTruncateElement
void GetRouteTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFl...
Definition: TrackUnit.cpp:17739
TRailGraphics::bm70grounddblred
Graphics::TBitmap * bm70grounddblred
Definition: GraphicUnit.h:468
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:87
TRailGraphics::gl75
Graphics::TBitmap * gl75
Definition: GraphicUnit.h:700
TAllRoutes::LockedRouteLockStartTime
TDateTime LockedRouteLockStartTime
Definition: TrackUnit.h:1711
TTrack::TSigElement::Attribute
int Attribute
the signal state - red, yellow, double yellow or green
Definition: TrackUnit.h:726
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5720
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:7206
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5747
TOneRoute::TRouteFlash::OverlayPlotted
bool OverlayPlotted
flag indicating the graphic that is currently displayed, true for the overlay (route-coloured)
Definition: TrackUnit.h:1530
TTrack::LeftPlatAllowed
Set< int, 1, 146 > LeftPlatAllowed
Definition: TrackUnit.h:589
TAllRoutes::TRouteElementPair
std::pair< int, unsigned int > TRouteElementPair
defines a specific element in a route, the first (int) value is the vector position in the AllRoutesV...
Definition: TrackUnit.h:1672
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:66
TRailGraphics::sm51
Graphics::TBitmap * sm51
Definition: GraphicUnit.h:842
TRailGraphics::sm77
Graphics::TBitmap * sm77
Definition: GraphicUnit.h:863
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1937
TPrefDirElement::GetRouteAutoSigsGraphicPtr
Graphics::TBitmap * GetRouteAutoSigsGraphicPtr()
picks up the blue route graphic (not used - superseded by GetRouteGraphicPtr)
Definition: TrackUnit.cpp:934
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:10393
TTrack::TActiveLevelCrossing::ReducedTimePenalty
bool ReducedTimePenalty
marker that is set when a train is present on one of the elements of the LC - used to provide a 3 min...
Definition: TrackUnit.h:619
TOneRoute::FindForwardTargetSignalAttribute
bool FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
Used when setting signal aspects for a route by working forwards through the route to see what the ne...
Definition: TrackUnit.cpp:17483
TRailGraphics::gl143
Graphics::TBitmap * gl143
Definition: GraphicUnit.h:628
TRailGraphics::sm70
Graphics::TBitmap * sm70
Definition: GraphicUnit.h:939
TAllRoutes::DiagonalFouledByRoute
bool DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
As above but only checks for a route (may or may not be a train present (new at v1....
Definition: TrackUnit.cpp:20073
TGraphicElement::VPos
int VPos
horizontal and vertical positions
Definition: TrackUnit.h:435
TAllRoutes::LockedRouteFoundDuringRouteBuilding
bool LockedRouteFoundDuringRouteBuilding
this flags the fact that a locked route has been found during route building in an existing linked ro...
Definition: TrackUnit.h:1702
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:69
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:610
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2833
TRailGraphics::bm73CallingOn
Graphics::TBitmap * bm73CallingOn
Definition: GraphicUnit.h:485
TTrack::TFixedTrackArray::FixedTrackPiece
TFixedTrackPiece FixedTrackPiece[FirstUnusedSpeedTagNumber]
the array member
Definition: TrackUnit.h:554
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:5900
TRailGraphics::LCBotHorMan
Graphics::TBitmap * LCBotHorMan
Definition: GraphicUnit.h:744
TRailGraphics::gl66
Graphics::TBitmap * gl66
Definition: GraphicUnit.h:688
TRailGraphics::bm69grounddblred
Graphics::TBitmap * bm69grounddblred
Definition: GraphicUnit.h:461
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Used for track at platforms and non-station named locations to mark the train front element stop posi...
Definition: TrackUnit.h:152
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:8233
TOneRoute::RouteSearchLimit
static const int RouteSearchLimit
limit to the number of elements searched in attempting to find a route
Definition: TrackUnit.h:1540
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:435
TTrack::TTrackVectorIterator
std::vector< TTrackElement >::iterator TTrackVectorIterator
iterator for TTrackVector
Definition: TrackUnit.h:648
TAllRoutes::ClearRouteDuringRouteBuildingAt
void ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
When attaching a new route section to an existing route, it is sometimes necessary to erase the origi...
Definition: TrackUnit.cpp:18752
TRailGraphics::sm108
Graphics::TBitmap * sm108
Definition: GraphicUnit.h:779
TTrack::Tag79Array
int Tag79Array[25][3]
Definition: TrackUnit.h:581
TRailGraphics::gl60
Graphics::TBitmap * gl60
Definition: GraphicUnit.h:682
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:12901
TRailGraphics::bm132
Graphics::TBitmap * bm132
Definition: GraphicUnit.h:361
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:7691
TRailGraphics::bm73
Graphics::TBitmap * bm73
Definition: GraphicUnit.h:484
TRailGraphics::bm30
Graphics::TBitmap * bm30
Definition: GraphicUnit.h:402
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:10260
TTrack::DecrementValuesInGapsAndTrackAndNameMaps
void DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the TrackVector, all the later elements are moved down one....
Definition: TrackUnit.cpp:9437
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:14294
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:48
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:15837
TRailGraphics::gl103
Graphics::TBitmap * gl103
Definition: GraphicUnit.h:582
TAllRoutes::GetAllRoutesTruncateElement
bool GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is prese...
Definition: TrackUnit.cpp:18278
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:19114
TRailGraphics::sm83
Graphics::TBitmap * sm83
Definition: GraphicUnit.h:873
TTrack::NoPlatsMessageSent
bool NoPlatsMessageSent
used to send no platforms warning once only
Definition: TrackUnit.h:758
TRailGraphics::sm81
Graphics::TBitmap * sm81
Definition: GraphicUnit.h:871
TRailGraphics::bm74grounddblwhite
Graphics::TBitmap * bm74grounddblwhite
Definition: GraphicUnit.h:495
TAllRoutes::TLockedRouteClass::LastXLinkPos
int LastXLinkPos
the XLinkPos value of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1652
TRailGraphics::sm97
Graphics::TBitmap * sm97
Definition: GraphicUnit.h:889
TRailGraphics::Concourse
Graphics::TBitmap * Concourse
Definition: GraphicUnit.h:549
TOnePrefDir::LoadOldPrefDir
void LoadOldPrefDir(int Caller, std::ifstream &VecFile)
Old version of LoadPrefDir, used during development when the save format changed so the old files cou...
Definition: TrackUnit.cpp:12705
TTrackElement::FourAspect
@ FourAspect
Definition: TrackUnit.h:160
TRailGraphics::bm9
Graphics::TBitmap * bm9
Definition: GraphicUnit.h:514
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:4484
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3671
TRailGraphics::gl67
Graphics::TBitmap * gl67
Definition: GraphicUnit.h:689
TRailGraphics::sm56
Graphics::TBitmap * sm56
Definition: GraphicUnit.h:847
TOneRoute::StartRoutePosition
int StartRoutePosition
TrackVectorPosition of the StartElement(s) set when the starting position of a new route is selected,...
Definition: TrackUnit.h:1552
TRailGraphics::bm69dblyellow
Graphics::TBitmap * bm69dblyellow
Definition: GraphicUnit.h:460
TRailGraphics::gl118
Graphics::TBitmap * gl118
Definition: GraphicUnit.h:598
TRailGraphics::sm105
Graphics::TBitmap * sm105
Definition: GraphicUnit.h:776
TRailGraphics::bm70dblyellow
Graphics::TBitmap * bm70dblyellow
Definition: GraphicUnit.h:467
TRailGraphics::sm24
Graphics::TBitmap * sm24
Definition: GraphicUnit.h:812
TTrack::CheckFootCrossingLinks
bool CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
True if a footcrossing is linked properly at both ends.
Definition: TrackUnit.cpp:8048
TGraphicElement::SourceRect
TRect SourceRect
source rectangle of the original graphic
Definition: TrackUnit.h:441
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:172
TRailGraphics::gl57
Graphics::TBitmap * gl57
Definition: GraphicUnit.h:678
TRailGraphics::gl120
Graphics::TBitmap * gl120
Definition: GraphicUnit.h:601
TPrefDirElement::GetDirectionRouteGraphicPtr
Graphics::TBitmap * GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
picks up the green or red route direction graphic
Definition: TrackUnit.cpp:1046
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4644
TOnePrefDir::TPrefDir4MultiMapEntry
std::pair< THVPair, unsigned int > TPrefDir4MultiMapEntry
Definition: TrackUnit.h:1334
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
Plot & open (to trains) all level crossings linked to TrackElement (Manual true = manually lowered,...
Definition: TrackUnit.cpp:6489
TTrack::OneNamedLocationElementAtLocation
bool OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
True if there is at least one named location element with name 'LocationName', used in timetable inte...
Definition: TrackUnit.cpp:10882
TRailGraphics::gl5
Graphics::TBitmap * gl5
Definition: GraphicUnit.h:670
TRailGraphics::bm94unset
Graphics::TBitmap * bm94unset
Definition: GraphicUnit.h:518
TRailGraphics::sm93
Graphics::TBitmap * sm93
Definition: GraphicUnit.h:884
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3547
Unused
@ Unused
Definition: TrackUnit.h:65
TRailGraphics::gl122
Graphics::TBitmap * gl122
Definition: GraphicUnit.h:603
TRailGraphics::gl15
Graphics::TBitmap * gl15
Definition: GraphicUnit.h:633
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TOnePrefDir::TPrefDir4MultiMapIterator
std::multimap< THVPair, unsigned int, TMapComp >::iterator TPrefDir4MultiMapIterator
Definition: TrackUnit.h:1333
TRailGraphics::bm74
Graphics::TBitmap * bm74
Definition: GraphicUnit.h:491
TRailGraphics::gl90set
Graphics::TBitmap * gl90set
Definition: GraphicUnit.h:721
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:19588
TrackUnit.h
TTrack::ReturnNextInactiveTrackElement
bool ReturnNextInactiveTrackElement(int Caller, TTrackElement &Next)
Return a reference to the inactive track element pointed to by NextTrackElementPtr (during zoomed-in ...
Definition: TrackUnit.cpp:2866
TRailGraphics::sm117
Graphics::TBitmap * sm117
Definition: GraphicUnit.h:786
TTrack::ResetAllTrainIDsAndFailedPointOrigSpeedLimits
void ResetAllTrainIDsAndFailedPointOrigSpeedLimits(int Caller)
Definition: TrackUnit.cpp:7677
TRailGraphics::FSig75
Graphics::TBitmap * FSig75
Definition: GraphicUnit.h:922
TPrefDirElement::IsARoute
bool IsARoute
false for Pref Dir, true for route
Definition: TrackUnit.h:225
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:19783
TTrack::Tag76Array
int Tag76Array[25][3]
these arrays give valid adjacent named element relative positions for each type of named element,...
Definition: TrackUnit.h:577
TTrack::LengthMarker
void LengthMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:9604
TAllRoutes::LockedRouteLastTrackVectorPosition
unsigned int LockedRouteLastTrackVectorPosition
Definition: TrackUnit.h:1710
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1550
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1639
TPrefDirElement::TrackVectorPosition
int TrackVectorPosition
TrackVectorPosition of the corresponding track element.
Definition: TrackUnit.h:207
TRailGraphics::sm121
Graphics::TBitmap * sm121
Definition: GraphicUnit.h:951
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:34
Utilities.h
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:729
TGraphicElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:439
TRailGraphics::sm46
Graphics::TBitmap * sm46
Definition: GraphicUnit.h:836
TTrack::SimpleVector
TSimpleVector SimpleVector
vector of simple element track vector positions
Definition: TrackUnit.h:820
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:3271
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:16005
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:34
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:221
TRailGraphics::sm131striped
Graphics::TBitmap * sm131striped
Definition: GraphicUnit.h:793
TRailGraphics::gl63
Graphics::TBitmap * gl63
Definition: GraphicUnit.h:685
TRailGraphics::bm75grounddblwhite
Graphics::TBitmap * bm75grounddblwhite
Definition: GraphicUnit.h:501
TTrack::AdjElement
bool AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
Used during location naming to check for adjacent named elements to a given element at HLoc & VLoc wi...
Definition: TrackUnit.cpp:8500
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:12967
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:808
Simple
@ Simple
Definition: TrackUnit.h:65
TRailGraphics::bm46
Graphics::TBitmap * bm46
Definition: GraphicUnit.h:445
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:71
TRailGraphics::bm72dblyellow
Graphics::TBitmap * bm72dblyellow
Definition: GraphicUnit.h:479
TRailGraphics::sm22
Graphics::TBitmap * sm22
Definition: GraphicUnit.h:810
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:2882
TTrack::TSigElement::SigPtr
Graphics::TBitmap * SigPtr
pointer to the graphic
Definition: TrackUnit.h:728
TRailGraphics::BridgeNonSigRouteGraphicsPtr
Graphics::TBitmap * BridgeNonSigRouteGraphicsPtr[12]
route graphic for unrestricted route overlay
Definition: GraphicUnit.h:1039
TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors
bool FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber)
If a route is present at H, V & Elink returns true with RouteNumber giving vector position in AllRout...
Definition: TrackUnit.cpp:18862
TRailGraphics::sm130
Graphics::TBitmap * sm130
Definition: GraphicUnit.h:791
TRailGraphics::sm45
Graphics::TBitmap * sm45
Definition: GraphicUnit.h:835
TRailGraphics::bm38
Graphics::TBitmap * bm38
Definition: GraphicUnit.h:426
TOnePrefDir::TPrefDirVectorIterator
std::vector< TPrefDirElement >::iterator TPrefDirVectorIterator
Definition: TrackUnit.h:1401
TRailGraphics::gl90unset
Graphics::TBitmap * gl90unset
Definition: GraphicUnit.h:722
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:13218
TTrack::WriteTrackAndTextToImage
void WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:3868
TGraphicElement::TGraphicElement
TGraphicElement()
Default constructor (16 x 16 pixel element)
Definition: TrackUnit.cpp:1743
TRailGraphics::gl129Striped
Graphics::TBitmap * gl129Striped
Definition: GraphicUnit.h:611
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:5860
TRailGraphics::gl64
Graphics::TBitmap * gl64
Definition: GraphicUnit.h:686
TTrain
Definition: TrainUnit.h:304
TPrefDirElement::TPrefDirElement
TPrefDirElement()
Default constructor, loads default values.
Definition: TrackUnit.h:379
TOnePrefDir::PresetAutoRouteDiagonalFouledByTrack
bool PresetAutoRouteDiagonalFouledByTrack(int Caller, TPrefDirElement ElementIn, int XLink)
Called by GetStartAndEndPrefDirElements...
Definition: TrackUnit.cpp:14165
TRailGraphics::bm77Striped
Graphics::TBitmap * bm77Striped
Definition: GraphicUnit.h:505
TFixedTrackPiece::TFixedTrackPiece
TFixedTrackPiece()
Default constructor.
Definition: TrackUnit.cpp:117
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:11618
TRailGraphics::bm74grounddblred
Graphics::TBitmap * bm74grounddblred
Definition: GraphicUnit.h:494
TRailGraphics::gl1
Graphics::TBitmap * gl1
Definition: GraphicUnit.h:577
TTrack::LinkCheckArray
int LinkCheckArray[9][2]
array of valid link connecting values, I don't think this is used now
Definition: TrackUnit.h:573
TRailGraphics::sm66
Graphics::TBitmap * sm66
Definition: GraphicUnit.h:858
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:629
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:7706
TRailGraphics::bm35
Graphics::TBitmap * bm35
Definition: GraphicUnit.h:417
TPerfLogForm::PerformanceLog
void PerformanceLog(int Caller, AnsiString Statement)
Send Statement to the performance log on screen and to the file.
Definition: PerfLogUnit.cpp:32
TRailGraphics::bm10
Graphics::TBitmap * bm10
Definition: GraphicUnit.h:348
GapJump
@ GapJump
Definition: TrackUnit.h:65
TRailGraphics::bm45
Graphics::TBitmap * bm45
Definition: GraphicUnit.h:444
TRailGraphics::sm19
Graphics::TBitmap * sm19
Definition: GraphicUnit.h:806
TAllRoutes::AddRouteElement
void AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2Mult...
Definition: TrackUnit.cpp:19223
TRailGraphics::sm82
Graphics::TBitmap * sm82
Definition: GraphicUnit.h:872
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:7452
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:150
TRailGraphics::bm71dblyellow
Graphics::TBitmap * bm71dblyellow
Definition: GraphicUnit.h:473
TRailGraphics::sm124
Graphics::TBitmap * sm124
Definition: GraphicUnit.h:954
TRailGraphics::bm69CallingOn
Graphics::TBitmap * bm69CallingOn
Definition: GraphicUnit.h:459
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:150
TTrack::Raising
@ Raising
Definition: TrackUnit.h:610
TRailGraphics::gl26
Graphics::TBitmap * gl26
Definition: GraphicUnit.h:644
TTrack::VLocMax
int VLocMax
give extent of railway for use in zoomed in and out displays and in saving railway images
Definition: TrackUnit.h:571
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:10498
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:585
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen
Definition: DisplayUnit.h:78
TOneRoute::StartElement2
TPrefDirElement StartElement2
the two preferred direction elements corresponding to the starting position of a new route
Definition: TrackUnit.h:1554
TOneRoute::TRouteFlashElement::VLoc
int VLoc
Definition: TrackUnit.h:1518
TRailGraphics::gl86
Graphics::TBitmap * gl86
Definition: GraphicUnit.h:714
TRailGraphics::bm134
Graphics::TBitmap * bm134
Definition: GraphicUnit.h:367
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:702
TTrack::Tag129Array
int Tag129Array[8][3]
Definition: TrackUnit.h:583
TTrack::InactiveTrack2MultiMap
TInactiveTrack2MultiMap InactiveTrack2MultiMap
multimap of inactive TrackElements (see type for more information above)
Definition: TrackUnit.h:810
TRailGraphics::bm14
Graphics::TBitmap * bm14
Definition: GraphicUnit.h:387
TRailGraphics::sm106
Graphics::TBitmap * sm106
Definition: GraphicUnit.h:777
TRailGraphics::bm68dblyellow
Graphics::TBitmap * bm68dblyellow
Definition: GraphicUnit.h:454
TRailGraphics::gl97
Graphics::TBitmap * gl97
Definition: GraphicUnit.h:731
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1410
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:6131
End
@ End
Definition: TrackUnit.h:75
TUserGraphicItem
Definition: DisplayUnit.h:31
TUtilities::FixedMinRepairTime
int FixedMinRepairTime
Definition: Utilities.h:66
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1556
TRailGraphics::gl62
Graphics::TBitmap * gl62
Definition: GraphicUnit.h:684
TRailGraphics::sm67
Graphics::TBitmap * sm67
Definition: GraphicUnit.h:859
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers - Raising, Lowering, Up, Down (an enum - see above)
Definition: TrackUnit.h:621
TTrack::TimetabledLocationNameAllocated
bool TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found as a timetabled location name i.e. not as a continuation name.
Definition: TrackUnit.cpp:8854
TRailGraphics::sm9
Graphics::TBitmap * sm9
Definition: GraphicUnit.h:880
TRailGraphics::sm68
Graphics::TBitmap * sm68
Definition: GraphicUnit.h:937
TDisplay::GetImage
TImage * GetImage()
Return a pointer to the screen image.
Definition: DisplayUnit.h:138
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:41
TTrack::TrackFinished
bool TrackFinished
marker for all Conn & ConnLinkPos values set & track complete
Definition: TrackUnit.h:566
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackVector.at(At)
Definition: TrackUnit.cpp:10607
TRailGraphics::LinkNonSigRouteGraphicsPtr
Graphics::TBitmap * LinkNonSigRouteGraphicsPtr[30]
unrestricted route graphic overlay
Definition: GraphicUnit.h:1052
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:302
TRailGraphics::sm28
Graphics::TBitmap * sm28
Definition: GraphicUnit.h:816
TTrack::RouteFailMessage
AnsiString RouteFailMessage
Definition: TrackUnit.h:744
clB0G5R0
#define clB0G5R0
Definition: GraphicUnit.h:71
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:816
TRailGraphics::gl114
Graphics::TBitmap * gl114
Definition: GraphicUnit.h:594
TRailGraphics::sm116
Graphics::TBitmap * sm116
Definition: GraphicUnit.h:947
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:124
TRailGraphics::LCLHSVer
Graphics::TBitmap * LCLHSVer
Definition: GraphicUnit.h:739
TRailGraphics::bm74dblyellow
Graphics::TBitmap * bm74dblyellow
Definition: GraphicUnit.h:493
TRailGraphics::sm103
Graphics::TBitmap * sm103
Definition: GraphicUnit.h:774
TUtilities::Format96HHMMSS
AnsiString Format96HHMMSS(TDateTime DateTime)
formats a TDateTime into an AnsiString of the form hh:mm:ss where hh runs from 00 to 95 & resets when...
Definition: Utilities.cpp:788
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3842
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:1023
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:875
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:1024
TPrefDirElement::PrefDirRoute
bool PrefDirRoute
marker within the route for preferred direction route element
Definition: TrackUnit.h:229
TTextHandler::WriteTextToImage
void WriteTextToImage(int Caller, Graphics::TBitmap *Bitmap)
write all items in TextVector to the railway image in 'Bitmap'
Definition: TextUnit.cpp:442
TRailGraphics::bmNameStriped
Graphics::TBitmap * bmNameStriped
Definition: GraphicUnit.h:526
TRailGraphics::gl88unset
Graphics::TBitmap * gl88unset
Definition: GraphicUnit.h:717
SignalPost
@ SignalPost
Definition: TrackUnit.h:65
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:9569
TRailGraphics::BridgeGraphicsPtr
Graphics::TBitmap * BridgeGraphicsPtr[12]
basic graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1033
TRailGraphics::bm69green
Graphics::TBitmap * bm69green
Definition: GraphicUnit.h:463
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:18266
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:505
TRailGraphics::sm132
Graphics::TBitmap * sm132
Definition: GraphicUnit.h:794
TPrefDirElement::operator!=
bool operator!=(TPrefDirElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:1091
TAllRoutes::TRoute2MultiMapIterator
TRoute2MultiMap::iterator TRoute2MultiMapIterator
Definition: TrackUnit.h:1676
TRailGraphics::sm20
Graphics::TBitmap * sm20
Definition: GraphicUnit.h:808
TRailGraphics::sm52
Graphics::TBitmap * sm52
Definition: GraphicUnit.h:843
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:7720
TRailGraphics::bm68yellow
Graphics::TBitmap * bm68yellow
Definition: GraphicUnit.h:458
TTrack::TInactiveTrackRange
std::pair< TInactiveTrack2MultiMapIterator, TInactiveTrack2MultiMapIterator > TInactiveTrackRange
range for TInactiveTrack2MultiMap
Definition: TrackUnit.h:671
TRailGraphics::bm31
Graphics::TBitmap * bm31
Definition: GraphicUnit.h:405
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway (...
Definition: TrackUnit.cpp:6898
TTrack::TTrackVector
std::vector< TTrackElement > TTrackVector
vector of TrackElements
Definition: TrackUnit.h:646
TPrefDirElement::AutoSignals
bool AutoSignals
marker within the route for an AutoSignal route element
Definition: TrackUnit.h:227
TRailGraphics::bm74CallingOn
Graphics::TBitmap * bm74CallingOn
Definition: GraphicUnit.h:492
TRailGraphics::gl76
Graphics::TBitmap * gl76
Definition: GraphicUnit.h:701
TRailGraphics::FSig71
Graphics::TBitmap * FSig71
Definition: GraphicUnit.h:918
FirstUnusedSpeedTagNumber
#define FirstUnusedSpeedTagNumber
Definition: TrackUnit.h:36
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:8893
TRailGraphics::sm71
Graphics::TBitmap * sm71
Definition: GraphicUnit.h:940
TRailGraphics::sm43
Graphics::TBitmap * sm43
Definition: GraphicUnit.h:833
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir ...
Definition: TrackUnit.cpp:18251
TRailGraphics::sm101
Graphics::TBitmap * sm101
Definition: GraphicUnit.h:772
Concourse
@ Concourse
Definition: TrackUnit.h:66
TTrack::BotPlatAllowed
Set< int, 1, 146 > BotPlatAllowed
Definition: TrackUnit.h:589
TRailGraphics::gl52
Graphics::TBitmap * gl52
Definition: GraphicUnit.h:673
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:828
TRailGraphics::sm29
Graphics::TBitmap * sm29
Definition: GraphicUnit.h:817
TConfiguration
TConfiguration
< describes the type of track link. 'End' is used for both buffer stop and continuation entry/exit po...
Definition: TrackUnit.h:74
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:13935
TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap
void DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
Called after ErasePrefDirElementAt to decrement the remaining PrefDirElementNumbers in 4MultiMap if t...
Definition: TrackUnit.cpp:13672
TTrackElement::LogTrack
AnsiString LogTrack(int Caller) const
Used to log track parameters for call stack logging.
Definition: TrackUnit.cpp:236
TRailGraphics::gl95unset
Graphics::TBitmap * gl95unset
Definition: GraphicUnit.h:730
TTrack::TrackVectorSize
int TrackVectorSize()
Return the number of active track elements.
Definition: TrackUnit.h:928
TTrackType
TTrackType
< describes the type of track element
Definition: TrackUnit.h:64
TRailGraphics::bm77
Graphics::TBitmap * bm77
Definition: GraphicUnit.h:504
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4569
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1887
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:95
TRailGraphics::bm39
Graphics::TBitmap * bm39
Definition: GraphicUnit.h:429
TRailGraphics::sm40
Graphics::TBitmap * sm40
Definition: GraphicUnit.h:830
TRailGraphics::bm41
Graphics::TBitmap * bm41
Definition: GraphicUnit.h:435
TRailGraphics::sm54
Graphics::TBitmap * sm54
Definition: GraphicUnit.h:845
TRailGraphics::bm72green
Graphics::TBitmap * bm72green
Definition: GraphicUnit.h:482
TRailGraphics::gl129
Graphics::TBitmap * gl129
Definition: GraphicUnit.h:610
TRailGraphics::sm31
Graphics::TBitmap * sm31
Definition: GraphicUnit.h:820
TGraphicElement::ExistingGraphicLoaded
bool ExistingGraphicLoaded
state flags
Definition: TrackUnit.h:433
TRailGraphics::bm74green
Graphics::TBitmap * bm74green
Definition: GraphicUnit.h:496
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:35
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:788
TRailGraphics::bm71grounddblred
Graphics::TBitmap * bm71grounddblred
Definition: GraphicUnit.h:474
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:47
TFixedTrackPiece::SmallGraphicPtr
Graphics::TBitmap * SmallGraphicPtr
the track bitmap for display on the zoomed-out railway
Definition: TrackUnit.h:93
TRailGraphics::bm40
Graphics::TBitmap * bm40
Definition: GraphicUnit.h:432
TRailGraphics::sm42
Graphics::TBitmap * sm42
Definition: GraphicUnit.h:832
TRailGraphics::gl111
Graphics::TBitmap * gl111
Definition: GraphicUnit.h:591
TTrack::IsATrackElementAdjacentToLink
bool IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
True if there is an element adjacent to LinkIn for element at HLoc & VLoc.
Definition: TrackUnit.cpp:11085
TAllRoutes::DecrementRouteNumbersInRoute2MultiMap
void DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
After a route has been erased from AllRoutesVector and its entries from Route2MultiMap,...
Definition: TrackUnit.cpp:19067
TTrack::BuildGapMapFromTrackVector
void BuildGapMapFromTrackVector(int Caller)
Examine TrackVector and whenever find a new gap pair enter it into GapMap.
Definition: TrackUnit.cpp:4807
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:160
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1906
TTrack::MultiplayerOverlayMap
TMultiplayerOverlayMap MultiplayerOverlayMap
Definition: TrackUnit.h:798
TRailGraphics::gl68
Graphics::TBitmap * gl68
Definition: GraphicUnit.h:690
TRailGraphics::sm18
Graphics::TBitmap * sm18
Definition: GraphicUnit.h:805
TRailGraphics::sm128
Graphics::TBitmap * sm128
Definition: GraphicUnit.h:958
TTrack::SuppressRouteFailMessage
bool SuppressRouteFailMessage
true if a message has been given in the search routine, to avoid giving multiple times and to avoid o...
Definition: TrackUnit.h:760
TTrack::FixedTrackArray
TFixedTrackArray FixedTrackArray
the FixedTrackPiece array object
Definition: TrackUnit.h:561
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:90
TRailGraphics::gl121
Graphics::TBitmap * gl121
Definition: GraphicUnit.h:602
TRailGraphics::LCBothHor
Graphics::TBitmap * LCBothHor
Definition: GraphicUnit.h:736
TRailGraphics::sm6
Graphics::TBitmap * sm6
Definition: GraphicUnit.h:851
TPrefDirElement::GetOriginalGraphicPtr
Graphics::TBitmap * GetOriginalGraphicPtr()
picks up the original (non-flashing) graphic for use during route flashing
Definition: TrackUnit.cpp:471
TTrack::TTrackMap
std::map< THVPair, unsigned int, TMapComp > TTrackMap
map of TrackElement TrackVectorPositions, HLoc & VLoc pair is the key
Definition: TrackUnit.h:656
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
As DiagonalFouledByRouteOrTrain (in TAllRoutes) but only checks for a train (may or may not be a rout...
Definition: TrackUnit.cpp:11330
TAllRoutes::IsThereARouteAtIDNumber
bool IsThereARouteAtIDNumber(int Caller, IDInt RouteID)
Returns true if there is a route with the given ID number - added at v1.3.1 (see function for details...
Definition: TrackUnit.cpp:19689
TTrack::NameAllowed
Set< int, 1, 146 > NameAllowed
Definition: TrackUnit.h:589
TRailGraphics::LinkSigRouteGraphicsPtr
Graphics::TBitmap * LinkSigRouteGraphicsPtr[30]
preferred direction route graphic overlay
Definition: GraphicUnit.h:1050
TRailGraphics::gl142
Graphics::TBitmap * gl142
Definition: GraphicUnit.h:627
TTrack::ReturnNextTrackElement
bool ReturnNextTrackElement(int Caller, TTrackElement &Next)
Return a reference to the active track element pointed to by NextTrackElementPtr (during zoomed-in or...
Definition: TrackUnit.cpp:2850
TRailGraphics::gl92unset
Graphics::TBitmap * gl92unset
Definition: GraphicUnit.h:726
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1562
TOneRoute::RouteImageMarker
void RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
Used when creating a bitmap image to display the route colours and direction arrows (as on screen dur...
Definition: TrackUnit.cpp:15168
TTrack::IsLCBarrierUpAtHV
bool IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc)
True if a closed (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7333
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:8690
TTrack::SetLCAttributeAtHV
void SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
Set LC attribute at H & V; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to tra...
Definition: TrackUnit.cpp:7412
TRailGraphics::gl61
Graphics::TBitmap * gl61
Definition: GraphicUnit.h:683
TRailGraphics::LCBotHor
Graphics::TBitmap * LCBotHor
Definition: GraphicUnit.h:737
TTrack::GetTrackElementFromAnyTrackMap
TTrackElement & GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector)
Return a reference to the element at HLoc & VLoc for any map and any vector (used for SelectPrefDir i...
Definition: TrackUnit.cpp:5771
TTrack::TLocationNameMultiMapEntry
std::pair< AnsiString, int > TLocationNameMultiMapEntry
Definition: TrackUnit.h:693
TRailGraphics::gl55
Graphics::TBitmap * gl55
Definition: GraphicUnit.h:676
TUtilities::CallLogPop
void CallLogPop(int Caller)
pops the last entry off the call stack, throws an error if called when empty
Definition: Utilities.cpp:50
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
km/h
Definition: TrainUnit.h:317
TTrack::TLNDone2MultiMapIterator
TLNDone2MultiMap::iterator TLNDone2MultiMapIterator
during naming of linked named location elements, '2' because there
Definition: TrackUnit.h:684
TOnePrefDir::PrefDir4MultiMap
TPrefDir4MultiMap PrefDir4MultiMap
the pref dir multimap - up to 4 values (up to 2 tracks per element each with 2 directions)
Definition: TrackUnit.h:1336
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:875
TRailGraphics::sm30
Graphics::TBitmap * sm30
Definition: GraphicUnit.h:819
TRailGraphics::bm85
Graphics::TBitmap * bm85
Definition: GraphicUnit.h:511
TRailGraphics::sm3
Graphics::TBitmap * sm3
Definition: GraphicUnit.h:818
TRailGraphics::bm70yellow
Graphics::TBitmap * bm70yellow
Definition: GraphicUnit.h:471
TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap
void GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2, int &PrefDirPos3)
Return up to 4 vector positions for a given HLoc & VLoc; unused values return -1.
Definition: TrackUnit.cpp:13306
TRailGraphics::sm110
Graphics::TBitmap * sm110
Definition: GraphicUnit.h:782
TRailGraphics::sm92
Graphics::TBitmap * sm92
Definition: GraphicUnit.h:883
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:12441
TAllRoutes::TRoute2MultiMapEntry
std::pair< THVPair, TRouteElementPair > TRoute2MultiMapEntry
Definition: TrackUnit.h:1677
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:85
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1729
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
stores '1' if the bool is true or '0' if false to the file, then a CR
Definition: Utilities.cpp:108
TPrefDirVector
std::vector< TPrefDirElement > TPrefDirVector
forward declaration because needed in TTrack
Definition: TrackUnit.h:45
TRailGraphics::sm69
Graphics::TBitmap * sm69
Definition: GraphicUnit.h:938
TRailGraphics::gl123
Graphics::TBitmap * gl123
Definition: GraphicUnit.h:604
TTrack::TSRVector
TFailedElementVector TSRVector
vector of failed points with track vector positions & repair times for use in failure handling (new a...
Definition: TrackUnit.h:794
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:12934
TTrack::TInfrastructureFailureEntry::TVPos
int TVPos
Definition: TrackUnit.h:711
TRailGraphics::gl48
Graphics::TBitmap * gl48
Definition: GraphicUnit.h:668
TOneRoute::ForceCancelRoute
void ForceCancelRoute(int Caller)
Cancel a route immediately if a train occupies it when travelling in the wrong direction (or occupies...
Definition: TrackUnit.cpp:17947
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3648
TTrackElement::PlotVariableTrackElement
void PlotVariableTrackElement(int Caller, TDisplay *Disp) const
Plot the element on the display 'variable' indicates that the element may be named and if so may be p...
Definition: TrackUnit.cpp:170
TOnePrefDir::StorePrefDirElement
void StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map.
Definition: TrackUnit.cpp:13625
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:11373
TTrack::ThisNamedLocationLongEnoughForSplit
bool ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos, int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
See above under 'OneNamedLocationLongEnoughForSplit'.
Definition: TrackUnit.cpp:10748
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1789
TRailGraphics::sm109
Graphics::TBitmap * sm109
Definition: GraphicUnit.h:780
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:940
TRailGraphics::bm74yellow
Graphics::TBitmap * bm74yellow
Definition: GraphicUnit.h:497
TTrack::Tag78Array
int Tag78Array[25][3]
Definition: TrackUnit.h:580
TTrack::PlotGap
void PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a gap on screen - may be set or unset.
Definition: TrackUnit.cpp:5954
TPrefDirElement::GetDirectionPrefDirGraphicPtr
Graphics::TBitmap * GetDirectionPrefDirGraphicPtr() const
picks up the EntryDirectionGraphicPtr for preferred directions
Definition: TrackUnit.cpp:1029
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:12754
Under
@ Under
Definition: TrackUnit.h:75
TRailGraphics::bm59
Graphics::TBitmap * bm59
Definition: GraphicUnit.h:451
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:828
TRailGraphics::gl84
Graphics::TBitmap * gl84
Definition: GraphicUnit.h:712
TTrack::TActiveLevelCrossing::BaseElementSpeedTag
int BaseElementSpeedTag
SpeedTag value for the base element of a level crossing.
Definition: TrackUnit.h:625
TTrackElement::operator!=
bool operator!=(TTrackElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:156
TTrack::ResetConnClkCheckUnsetGapJumps
bool ResetConnClkCheckUnsetGapJumps(int Caller)
Sets all Conns and CLks to -1 except for gapjumps that match and are properly set,...
Definition: TrackUnit.cpp:2905
TOnePrefDir::GetModifiablePrefDirElementAt
TPrefDirElement & GetModifiablePrefDirElementAt(int Caller, int At)
Return a modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:11630
TOnePrefDir::SearchForPrefDir
bool SearchForPrefDir(int Caller, TTrackElement TrackElement, int XLinkPos, int RequiredPosition)
Try to find a selected element from a given start position. Enter with CurrentTrackElement stored in ...
Definition: TrackUnit.cpp:11949
TRailGraphics::sm96
Graphics::TBitmap * sm96
Definition: GraphicUnit.h:887
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:430
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:134
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:121
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:55
TTrack::OneNamedLocationLongEnoughForSplit
bool OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
Definition: TrackUnit.cpp:10642
Lead
@ Lead
Definition: TrackUnit.h:75
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:5819
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1823
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:13873
TTrack::PlotContinuation
void PlotContinuation(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a continuation on screen, may have overlays if a multiplayer session.
Definition: TrackUnit.cpp:6031
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:894
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:555
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:238
TTrack::TrackPush
void TrackPush(int Caller, TTrackElement TrackElement)
Insert TrackElement into the relevant vector and map, and, if named, insert the name in LocationNameM...
Definition: TrackUnit.cpp:5611
TTrack::IsBarrierDownVectorAtHVManual
bool IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
True if there is a vector entry at H & V that is set to manual (TypeOfRoute == 2) and returns the vec...
Definition: TrackUnit.cpp:6470
TFixedTrackPiece::FixedNamedLocationElement
bool FixedNamedLocationElement
true for an element that can be named (platforms, concourse, footcrossings & non-station named loacti...
Definition: TrackUnit.h:85
TUtilities::SignalChangeEventsPerFailure
int SignalChangeEventsPerFailure
number of signal changes between failures - reciprocal of failure probability per change
Definition: Utilities.h:85
TOnePrefDir::PrefDirSearchLimit
static const int PrefDirSearchLimit
limit to the number of elements searched in attempting to find a preferred direction
Definition: TrackUnit.h:1365
TTrack::GetTrackVectorIteratorFromNamePosition
TTrackVectorIterator GetTrackVectorIteratorFromNamePosition(int Caller, int Position)
Takes an adjusted vector position value from either vector (if active, Position = -TruePos -1,...
Definition: TrackUnit.cpp:9365
TRailGraphics::bm70grounddblwhite
Graphics::TBitmap * bm70grounddblwhite
Definition: GraphicUnit.h:469
TRailGraphics::bm70green
Graphics::TBitmap * bm70green
Definition: GraphicUnit.h:470
TRailGraphics::gl115
Graphics::TBitmap * gl115
Definition: GraphicUnit.h:595
TTrack::TInfrastructureFailureEntry
Definition: TrackUnit.h:710
TTrack::Up
@ Up
Definition: TrackUnit.h:610
TRailGraphics::sm89
Graphics::TBitmap * sm89
Definition: GraphicUnit.h:879
TTrack::NextTrackElementPtr
TTrackVectorIterator NextTrackElementPtr
track vector iterator used during cycling through a track vector
Definition: TrackUnit.h:830
TTrack::Tag130Array
int Tag130Array[8][3]
Definition: TrackUnit.h:584
TTrack::BlankElementAt
bool BlankElementAt(int Caller, int At) const
True for a blank (SpeedTag == 0) element at a specific Trackvector position, no longer used after Tra...
Definition: TrackUnit.cpp:10621
TRailGraphics::sm127
Graphics::TBitmap * sm127
Definition: GraphicUnit.h:957
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1512
TDisplay::PlotSignalBlankOnBitmap
void PlotSignalBlankOnBitmap(int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *Bitmap, bool RHSFlag)
Definition: DisplayUnit.cpp:378
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:8657
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1670
TTrack::LCFoundInAutoSigsRoute
bool LCFoundInAutoSigsRoute
true if found an LC during an automatic route search
Definition: TrackUnit.h:756
TPrefDirElement::XLink
int XLink
Definition: TrackUnit.h:203
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:18014
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1659
TRailGraphics::bm133
Graphics::TBitmap * bm133
Definition: GraphicUnit.h:364
TRailGraphics::sm135
Graphics::TBitmap * sm135
Definition: GraphicUnit.h:797
Crossover
@ Crossover
Definition: TrackUnit.h:65
TTrack::SetLinkedManualLCs
void SetLinkedManualLCs(int Caller, int HLoc, int VLoc)
Set all TypeOfRoute values to 2 for all linked LCs to indicate manually lowered.
Definition: TrackUnit.cpp:6356
TRailGraphics::bm71green
Graphics::TBitmap * bm71green
Definition: GraphicUnit.h:476
TRailGraphics::bm51
Graphics::TBitmap * bm51
Definition: GraphicUnit.h:447
TTrack::UGME
TUserGraphicMapEntry UGME
an entry for the UserGraphicMap
Definition: TrackUnit.h:832
TRailGraphics::gl21
Graphics::TBitmap * gl21
Definition: GraphicUnit.h:639
TTrack::ElementInLNDone2MultiMap
bool ElementInLNDone2MultiMap(int Caller, int MapPos)
True if the element defined by MapPos is present in LNDone2MultiMap, used during location naming.
Definition: TrackUnit.cpp:8603
TRailGraphics::sm137
Graphics::TBitmap * sm137
Definition: GraphicUnit.h:799
TRailGraphics::BlackOctagon
Graphics::TBitmap * BlackOctagon
Definition: GraphicUnit.h:574
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:7361
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:10032
TRailGraphics::bm68CallingOn
Graphics::TBitmap * bm68CallingOn
Definition: GraphicUnit.h:453
Signal
@ Signal
Definition: TrackUnit.h:75
TTrack::VLocMin
int VLocMin
Definition: TrackUnit.h:571
TTrack::LevelCrossingAllowed
Set< int, 1, 146 > LevelCrossingAllowed
sets of valid TrackElements for placement of platforms and non-station named locations
Definition: TrackUnit.h:589
TRailGraphics::bm69grounddblwhite
Graphics::TBitmap * bm69grounddblwhite
Definition: GraphicUnit.h:462
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:796
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:18555
TTrack::TFixedTrackArray::TFixedTrackArray
TFixedTrackArray()
Array constructor.
Definition: TrackUnit.cpp:1557
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:12804
TRailGraphics::bm78Striped
Graphics::TBitmap * bm78Striped
Definition: GraphicUnit.h:507
TTrack::TrainOnLink
bool TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID)
New at v1.2.0; checks whether a train present at input location and link and returns its ID if so.
Definition: TrackUnit.cpp:11269
TTrack::ResetAnyNonMatchingGaps
void ResetAnyNonMatchingGaps(int Caller)
Called by EraseTrackElement after the element has been erased and the vector positions changed,...
Definition: TrackUnit.cpp:4653
TTrack::GapPos
int GapPos
Definition: TrackUnit.h:569
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackVector.at(At)
Definition: TrackUnit.cpp:10593
TGraphicElement::Width
int Width
Definition: TrackUnit.h:437
TAllRoutes::RouteLockingRequired
bool RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTru...
Definition: TrackUnit.cpp:19463
TRailGraphics::bmGreenEllipse
Graphics::TBitmap * bmGreenEllipse
Definition: GraphicUnit.h:521
TAllRoutes::GetRouteVectorNumber
int GetRouteVectorNumber(int Caller, IDInt RouteID)
Returns a route's position in AllRoutesVector from its ID, throws an error if a matching route isn't ...
Definition: TrackUnit.cpp:19673
TAllRoutes::GetRouteTypeAndGraphics
TRouteType GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap *&EXGraphicPtr, Graphics::TBitmap *&EntryDirectionGraphicPtr)
Examines Route2MultiMap for the element at TrackVectorPosition with LinkPos (can be entry or exit).
Definition: TrackUnit.cpp:18381
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:802
TRailGraphics::bm73green
Graphics::TBitmap * bm73green
Definition: GraphicUnit.h:489
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:795
TRailGraphics::gl107
Graphics::TBitmap * gl107
Definition: GraphicUnit.h:586
TPrefDirElement::GetRouteGraphicPtr
Graphics::TBitmap * GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
picks up the appropriate route graphic
Definition: TrackUnit.cpp:663
TRailGraphics::bm53
Graphics::TBitmap * bm53
Definition: GraphicUnit.h:448
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or ' ' (CRLF) accepted as delimiters), returns true for succes...
Definition: Utilities.cpp:529
TRailGraphics::sm12
Graphics::TBitmap * sm12
Definition: GraphicUnit.h:787
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:33
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:14702
TTrack::TTrackMapIterator
TTrackMap::iterator TTrackMapIterator
Definition: TrackUnit.h:658
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:4150
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2368
TTrack::TLocationNameMultiMapIterator
TLocationNameMultiMap::iterator TLocationNameMultiMapIterator
Definition: TrackUnit.h:691
TRailGraphics::bm70CallingOn
Graphics::TBitmap * bm70CallingOn
Definition: GraphicUnit.h:466
TTrack::RebuildLocationNameMultiMap
void RebuildLocationNameMultiMap(int Caller)
Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector....
Definition: TrackUnit.cpp:9505
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green ...
Definition: TrackUnit.cpp:12572
TRailGraphics::gl124
Graphics::TBitmap * gl124
Definition: GraphicUnit.h:605
TTrack::FailedSignalsVector
TFailedElementVector FailedSignalsVector
Definition: TrackUnit.h:794
TRailGraphics::bm32
Graphics::TBitmap * bm32
Definition: GraphicUnit.h:408
TRailGraphics::sm88
Graphics::TBitmap * sm88
Definition: GraphicUnit.h:878
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:967
TTrack::GetInactiveTrackElementFromTrackMap
TTrackElement & GetInactiveTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the inactive element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5795
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:19756
TRailGraphics::gl105
Graphics::TBitmap * gl105
Definition: GraphicUnit.h:584
TOneRoute::StartElement1
TPrefDirElement StartElement1
Definition: TrackUnit.h:1554
TRailGraphics::sm75
Graphics::TBitmap * sm75
Definition: GraphicUnit.h:944
TRailGraphics::sm115
Graphics::TBitmap * sm115
Definition: GraphicUnit.h:785
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1543
TRailGraphics::sm53
Graphics::TBitmap * sm53
Definition: GraphicUnit.h:844
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement - always plots as red - auto.
Definition: TrackUnit.cpp:7059
TRailGraphics::bm71CallingOn
Graphics::TBitmap * bm71CallingOn
Definition: GraphicUnit.h:472
TTrack::LCFoundInRouteBuildingFlag
bool LCFoundInRouteBuildingFlag
true if a route set through an LC that is closed to trains (& therefore needs to be opened)
Definition: TrackUnit.h:762
TRailGraphics::DirectionSigRouteGraphicsPtr
Graphics::TBitmap * DirectionSigRouteGraphicsPtr[10]
preferred direction route marker arrows
Definition: GraphicUnit.h:1063
TRailGraphics::DirectionRouteAutoSigsGraphicsPtr
Graphics::TBitmap * DirectionRouteAutoSigsGraphicsPtr[10]
autosigs route marker arrows
Definition: GraphicUnit.h:1065
TRailGraphics::bm93set
Graphics::TBitmap * bm93set
Definition: GraphicUnit.h:515
TTrack::GetTrackVectorPositionFromString
int GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
Takes the ElementID value (an AnsiString) (e.g. "8-13", "N43-N127", etc) and returns the correspondin...
Definition: TrackUnit.cpp:7892
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:18106
TTrack::TTrackMapEntry
std::pair< THVPair, unsigned int > TTrackMapEntry
Definition: TrackUnit.h:659
TRailGraphics::bm37
Graphics::TBitmap * bm37
Definition: GraphicUnit.h:423
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:7434
TRailGraphics::sm139
Graphics::TBitmap * sm139
Definition: GraphicUnit.h:801
Erase
@ Erase
Definition: TrackUnit.h:66
TRailGraphics::sm57
Graphics::TBitmap * sm57
Definition: GraphicUnit.h:848
TRailGraphics::bm29
Graphics::TBitmap * bm29
Definition: GraphicUnit.h:399
TRailGraphics::bm72grounddblwhite
Graphics::TBitmap * bm72grounddblwhite
Definition: GraphicUnit.h:481
TTrack::IsTrackLinked
bool IsTrackLinked(int Caller)
True if track has been successfully linked (not used any more)
Definition: TrackUnit.cpp:5416
TTrack::NewVector
TTrackVector NewVector
Definition: TrackUnit.h:828
TAllRoutes::LockedRouteTruncateTrackVectorPosition
unsigned int LockedRouteTruncateTrackVectorPosition
Definition: TrackUnit.h:1709
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:127
TRailGraphics::sm39
Graphics::TBitmap * sm39
Definition: GraphicUnit.h:828
TRailGraphics::sm85
Graphics::TBitmap * sm85
Definition: GraphicUnit.h:875
TRailGraphics::gl112
Graphics::TBitmap * gl112
Definition: GraphicUnit.h:592
TOnePrefDir::GetExactMatchFrom4MultiMap
TPrefDir4MultiMapIterator GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition....
Definition: TrackUnit.cpp:13695
TTrack::TActiveLevelCrossing::TypeOfRoute
int TypeOfRoute
route type - 0 = nonsignals, 1 = preferred direction (can't have autosigs), 2 no route,...
Definition: TrackUnit.h:617
TTrack::GetAnyElementOppositeLinkPos
int GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
Return the opposite link position for the element at TrackVectorPosition with link position LinkPos,...
Definition: TrackUnit.cpp:11181
Parapet
@ Parapet
Definition: TrackUnit.h:66
TRailGraphics::bm54
Graphics::TBitmap * bm54
Definition: GraphicUnit.h:449
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:18225
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:105
TRailGraphics::sm14
Graphics::TBitmap * sm14
Definition: GraphicUnit.h:802
TRailGraphics::bmStraightEWSignalBlank
Graphics::TBitmap * bmStraightEWSignalBlank
Definition: GraphicUnit.h:1027
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:272
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:9174
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:18079
TRailGraphics::bm138
Graphics::TBitmap * bm138
Definition: GraphicUnit.h:379
TRailGraphics::sm79striped
Graphics::TBitmap * sm79striped
Definition: GraphicUnit.h:868
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:828
TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap
void DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap,...
Definition: TrackUnit.cpp:19090
TRailGraphics::gl126
Graphics::TBitmap * gl126
Definition: GraphicUnit.h:607
TRailGraphics::sm119
Graphics::TBitmap * sm119
Definition: GraphicUnit.h:949
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
< map of coupled continuations
Definition: TrackUnit.h:800
TRailGraphics::sm138
Graphics::TBitmap * sm138
Definition: GraphicUnit.h:800
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:148
TRailGraphics::bm72grounddblred
Graphics::TBitmap * bm72grounddblred
Definition: GraphicUnit.h:480
TRailGraphics::sm34
Graphics::TBitmap * sm34
Definition: GraphicUnit.h:823
TDisplay::PlotPointBlank
void PlotPointBlank(int Caller, int HLoc, int VLoc)
Definition: DisplayUnit.cpp:247
TRailGraphics::ConcourseStriped
Graphics::TBitmap * ConcourseStriped
Definition: GraphicUnit.h:551
TRailGraphics::FSig72
Graphics::TBitmap * FSig72
Definition: GraphicUnit.h:919
TRailGraphics::PointModeGraphicsPtr
Graphics::TBitmap * PointModeGraphicsPtr[32][2]
for point fillets - 32 sets of points, each with two fillets
Definition: GraphicUnit.h:1068
TTrack::SigTableTwoAspect
TSigElement SigTableTwoAspect[40]
new at version 0.6 for two aspect
Definition: TrackUnit.h:736
TRailGraphics::sm27
Graphics::TBitmap * sm27
Definition: GraphicUnit.h:815
TTrainController::LogActionError
void LogActionError(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionEventType ActionEventType, AnsiString LocationID)
Send an error message to the performance log and file, and as a warning if appropriate.
Definition: TrainUnit.cpp:15436
TRailGraphics::sm5
Graphics::TBitmap * sm5
Definition: GraphicUnit.h:840
TTrackElement::LCPlotted
bool LCPlotted
Utility marker to avoid plotting every element of a multitrack LC during ClearandRebuildRailway.
Definition: TrackUnit.h:136
Nil
@ Nil
Definition: Utilities.h:37
TPrefDirElement::EXNumber
int EXNumber
used to facilitate identification of the appropriate preferred direction or route graphic
Definition: TrackUnit.h:205
TTrack::NumberOfPlatforms
int NumberOfPlatforms(int Caller, AnsiString LocationName)
Returns the number of separate platforms (not platform elements) at a given location,...
Definition: TrackUnit.cpp:11401
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track marker, including direction markers.
Definition: TrackUnit.cpp:12499
TRailGraphics::bm78
Graphics::TBitmap * bm78
Definition: GraphicUnit.h:506
TTruncateReturnType
TTruncateReturnType
< a flag used during route truncation to indicate the nature of the selected element,...
Definition: TrackUnit.h:1314
TRailGraphics::bm75CallingOn
Graphics::TBitmap * bm75CallingOn
Definition: GraphicUnit.h:498
TRailGraphics::FSig70
Graphics::TBitmap * FSig70
Definition: GraphicUnit.h:917
TOneRoute::SetLCChangeValues
void SetLCChangeValues(int Caller, bool PrefDirRoute)
After a route has been selected successfully this function sets all LC change values appropriately fo...
Definition: TrackUnit.cpp:18042
TRailGraphics::gl130
Graphics::TBitmap * gl130
Definition: GraphicUnit.h:613
TRailGraphics::FSig74
Graphics::TBitmap * FSig74
Definition: GraphicUnit.h:921
TRailGraphics::bm71yellow
Graphics::TBitmap * bm71yellow
Definition: GraphicUnit.h:477
TRailGraphics::LCRHSVerMan
Graphics::TBitmap * LCRHSVerMan
Definition: GraphicUnit.h:748
TTrack
Definition: TrackUnit.h:547
TOnePrefDir::SearchLimitHighH
int SearchLimitHighH
Definition: TrackUnit.h:1373
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:875
TOnePrefDir::PrefDirVector
TPrefDirVector PrefDirVector
Definition: TrackUnit.h:1404
TAllRoutes::SetTrailingSignalsOnAutoSigsRoute
void SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
Enter with signal at TrackVectorElement already set to red by the passing train.
Definition: TrackUnit.cpp:19239
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:286
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:73
TAllRoutes::TLockedRouteClass::RouteNumber
int RouteNumber
the vector position number of the relevant route in AllRoutesVector
Definition: TrackUnit.h:1646
TTrack::ActiveMapCheck
bool ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:8202
TRailGraphics::gl2
Graphics::TBitmap * gl2
Definition: GraphicUnit.h:637
TTrack::Tag146Array
int Tag146Array[8][3]
Definition: TrackUnit.h:587
TRailGraphics::sm65
Graphics::TBitmap * sm65
Definition: GraphicUnit.h:857
TRailGraphics::gl47
Graphics::TBitmap * gl47
Definition: GraphicUnit.h:667
TRailGraphics::LCBothHorMan
Graphics::TBitmap * LCBothHorMan
Definition: GraphicUnit.h:743
TRailGraphics::sm78striped
Graphics::TBitmap * sm78striped
Definition: GraphicUnit.h:866
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:127
TRailGraphics::sm33
Graphics::TBitmap * sm33
Definition: GraphicUnit.h:822
TRailGraphics::bm94set
Graphics::TBitmap * bm94set
Definition: GraphicUnit.h:517
TRailGraphics::gl76Striped
Graphics::TBitmap * gl76Striped
Definition: GraphicUnit.h:702
TPrefDirElement::XLinkPos
int XLinkPos
exit link number & array position
Definition: TrackUnit.h:203
TAllRoutes::StoreOneRouteAfterSessionLoad
void StoreOneRouteAfterSessionLoad(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load....
Definition: TrackUnit.cpp:18730
TUtilities::DelayMode
TDelayMode DelayMode
specifies whether no delays or minor, moderate or major random delays are to be applied (added at v2....
Definition: Utilities.h:107
TPrefDirElement::EntryDirectionGraphicPtr
Graphics::TBitmap * EntryDirectionGraphicPtr
pointers to the appropriate entry/exit graphic, or direction marker graphic, for preferred directions...
Definition: TrackUnit.h:211
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:2985
TRailGraphics::bm65
Graphics::TBitmap * bm65
Definition: GraphicUnit.h:452
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:9525
TRailGraphics::sm74
Graphics::TBitmap * sm74
Definition: GraphicUnit.h:943
TTrack::PlotSignalPlatforms
void PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
Plot platforms if any for a signal graphic - plotted before signal so shows through transparent signa...
Definition: TrackUnit.cpp:6250
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:2120
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:135
TTrack::Tag145Array
int Tag145Array[8][3]
Definition: TrackUnit.h:586
TRailGraphics::LCRHSVer
Graphics::TBitmap * LCRHSVer
Definition: GraphicUnit.h:741
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:160
TTrackElement::TTrackElement
TTrackElement()
Constructor for non-specific default element. Use high neg numbers for 'unset' h & v as can go high n...
Definition: TrackUnit.h:166
TRailGraphics::sm76
Graphics::TBitmap * sm76
Definition: GraphicUnit.h:861
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:808
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2586
TPrefDirElement::ELinkPos
int ELinkPos
entry link number & array position
Definition: TrackUnit.h:201
TAllRoutes::TLockedRouteClass
Handles routes that are locked because of approaching trains.
Definition: TrackUnit.h:1644
TTrack::SetElementID
void SetElementID(int Caller, TTrackElement &TrackElement)
Convert the position values for the TrackElement into an identification string and load in ElementID.
Definition: TrackUnit.cpp:7856
TRailGraphics::bm72yellow
Graphics::TBitmap * bm72yellow
Definition: GraphicUnit.h:483
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:12287
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:13065
TTrack::Tag131Array
int Tag131Array[4][3]
Definition: TrackUnit.h:585
TOneRoute::TRouteFlashElement::TrackVectorPosition
int TrackVectorPosition
element values
Definition: TrackUnit.h:1518
TTrack::RetrieveStripedNamedLocationGraphicsWhereRelevant
Graphics::TBitmap * RetrieveStripedNamedLocationGraphicsWhereRelevant(int Caller, TTrackElement TrackElement)
Return a pointer to the striped (i.e. when unnamed) graphic corresponding to TrackElement,...
Definition: TrackUnit.cpp:10530
TTrack::AddName
void AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
TrackElement.LocationName becomes 'Name' (for active and inactive elements) and, if TrackElement is a...
Definition: TrackUnit.cpp:8566
IDInt
Definition: TrackUnit.h:496
TTrain::GetLeadElement
void GetLeadElement(int Caller)
Called when a train is about to leave an element and move onto another.
Definition: TrainUnit.cpp:2579
TRailGraphics::gl110
Graphics::TBitmap * gl110
Definition: GraphicUnit.h:590
TAllRoutes::GetModifiableRouteAtIDNumber
TOneRoute & GetModifiableRouteAtIDNumber(int Caller, IDInt RouteID)
Returns a modifiable reference to the route with ID number RouteID. If no route is found with that ID...
Definition: TrackUnit.cpp:19724
TRailGraphics::gl130Striped
Graphics::TBitmap * gl130Striped
Definition: GraphicUnit.h:614
TRailGraphics::sm133
Graphics::TBitmap * sm133
Definition: GraphicUnit.h:795
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:4457
TDisplay
Definition: DisplayUnit.h:48
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:10280
TRailGraphics::FSig69
Graphics::TBitmap * FSig69
Definition: GraphicUnit.h:916
TTrack::LinkTrackNoMessages
bool LinkTrackNoMessages(int Caller, bool FinalCall)
Attempt to link the track and return true if successful, don't issue any screen messages....
Definition: TrackUnit.cpp:5161
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:146
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:867
TRailGraphics::sm129striped
Graphics::TBitmap * sm129striped
Definition: GraphicUnit.h:789
TRailGraphics::sm48
Graphics::TBitmap * sm48
Definition: GraphicUnit.h:838
TGraphicElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
original and temporary overlay graphics
Definition: TrackUnit.h:439
TAllRoutes::CheckForLoopingRoute
bool CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
Functions defined in .cpp file.
Definition: TrackUnit.cpp:19821
TTrack::TTrack
TTrack()
Constructor, only one object of this class.
Definition: TrackUnit.cpp:1126
TTrack::FindNamedElementInLocationNameMultiMap
TLocationNameMultiMapIterator FindNamedElementInLocationNameMultiMap(int Caller, AnsiString LocationName, TTrackVectorIterator TrackElement, AnsiString &ErrorString)
Searches LocationNameMultiMap to check if the element pointed to by the TTrackVectorIterator has the ...
Definition: TrackUnit.cpp:9288
TTrackElement::operator==
bool operator==(TTrackElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:142
TTrack::GapHLoc
int GapHLoc
Definition: TrackUnit.h:569
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:96
TTrack::CheckGapMap
void CheckGapMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:7803
NotInRoute
@ NotInRoute
Definition: TrackUnit.h:1315
TDisplay::GetRectangle
void GetRectangle(int Caller, TRect DestRect, TRect SourceRect, Graphics::TBitmap *&OriginalGraphic)
Definition: DisplayUnit.cpp:227
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:154
TTrackElement::Failed
bool Failed
New parameter added at v2.13.0 for failed points & TSRs.
Definition: TrackUnit.h:140
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:903
TOnePrefDir::FindLinkingPrefDir
bool FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
Finds a pref dir element that links to another element at given vector number and link number & posit...
Definition: TrackUnit.cpp:13375
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:784
TRailGraphics::LCPlainMan
Graphics::TBitmap * LCPlainMan
Definition: GraphicUnit.h:747
TRailGraphics::bm139
Graphics::TBitmap * bm139
Definition: GraphicUnit.h:382
TRailGraphics::gl3
Graphics::TBitmap * gl3
Definition: GraphicUnit.h:648
TPrefDirElement::CheckCount
int CheckCount
internal check value used when building preferred directions
Definition: TrackUnit.h:209
TRailGraphics::bm20
Graphics::TBitmap * bm20
Definition: GraphicUnit.h:394
TRailGraphics::sm77striped
Graphics::TBitmap * sm77striped
Definition: GraphicUnit.h:864
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:14499
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1714
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:162
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:129
TRailGraphics::sm112
Graphics::TBitmap * sm112
Definition: GraphicUnit.h:784
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7771
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:631
TRailGraphics::sm36
Graphics::TBitmap * sm36
Definition: GraphicUnit.h:825
TRailGraphics::sm136
Graphics::TBitmap * sm136
Definition: GraphicUnit.h:798
TRailGraphics::gl98
Graphics::TBitmap * gl98
Definition: GraphicUnit.h:732
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:148
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:910
TRailGraphics::sm100
Graphics::TBitmap * sm100
Definition: GraphicUnit.h:771
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1529
TRailGraphics::sm63
Graphics::TBitmap * sm63
Definition: GraphicUnit.h:855
TAllRoutes::TLockedRouteClass::LastTrackVectorPosition
unsigned int LastTrackVectorPosition
the TrackVector position of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1650
TRailGraphics::sm60
Graphics::TBitmap * sm60
Definition: GraphicUnit.h:852
TAllRoutes::NoRoute
@ NoRoute
Definition: TrackUnit.h:1660
TRailGraphics::bm42
Graphics::TBitmap * bm42
Definition: GraphicUnit.h:438
TTrack::RepositionAndMapTrack
bool RepositionAndMapTrack(int Caller)
When track is being built it is entered into the TrackVector in the order in which it is built,...
Definition: TrackUnit.cpp:4729
TRailGraphics::gl108
Graphics::TBitmap * gl108
Definition: GraphicUnit.h:587
TTrack::AdjNamedElement
bool AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
Used in SearchForAndUpdateLocationName to check for adjacent named elements to a given element at HLo...
Definition: TrackUnit.cpp:9114
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:708
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:15811
TOnePrefDir::ClearPrefDir
void ClearPrefDir()
Empty the existing vectors & map.
Definition: TrackUnit.h:1343
TRailGraphics::gl99
Graphics::TBitmap * gl99
Definition: GraphicUnit.h:733
TGraphicElement::OverlayLoaded
bool OverlayLoaded
Definition: TrackUnit.h:433
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:13801
TRailGraphics::sm4
Graphics::TBitmap * sm4
Definition: GraphicUnit.h:829
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1321
TOnePrefDir::BiDirectionalPrefDir
bool BiDirectionalPrefDir(int Caller, TPrefDir4MultiMapIterator PDPtr)
Determines whether the preferred direction pointed to has another pref dir in the opposite direction ...
Definition: TrackUnit.cpp:13576
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:152
TRailGraphics::gl89unset
Graphics::TBitmap * gl89unset
Definition: GraphicUnit.h:719
Points
@ Points
Definition: TrackUnit.h:65
TRailGraphics::LCPlain
Graphics::TBitmap * LCPlain
Definition: GraphicUnit.h:740
TAllRoutes::FindRoutePairFromRoute2MultiMap
TRouteElementPair FindRoutePairFromRoute2MultiMap(int Caller, int HLoc, int VLoc, int ELink, TRoute2MultiMapIterator &Route2MultiMapIterator)
Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H,...
Definition: TrackUnit.cpp:18803
TRailGraphics::sm80
Graphics::TBitmap * sm80
Definition: GraphicUnit.h:870
TTrack::IsElementDefaultLength
bool IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
Definition: TrackUnit.cpp:9963
TTrack::PopulateLCVector
void PopulateLCVector(int Caller)
Add all LCs to LCVector - note that this contains all LC elements whether linked to others or not.
Definition: TrackUnit.cpp:11252
TRailGraphics::bm33
Graphics::TBitmap * bm33
Definition: GraphicUnit.h:411
TRailGraphics::gl119
Graphics::TBitmap * gl119
Definition: GraphicUnit.h:599
TRailGraphics::sm47
Graphics::TBitmap * sm47
Definition: GraphicUnit.h:837
TRailGraphics::bm75grounddblred
Graphics::TBitmap * bm75grounddblred
Definition: GraphicUnit.h:500
TTrack::WriteOperatingTrackAndTextToImage
void WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track & text to the image file in their ope...
Definition: TrackUnit.cpp:4172
Trail
@ Trail
Definition: TrackUnit.h:75
TOneRoute::SetRouteSearchVectorGraphics
void SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector so that the...
Definition: TrackUnit.cpp:17991
TTrack::ChangeLocationNameMultiMapEntry
void ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationN...
Definition: TrackUnit.cpp:9347
TOneRoute::SetRearwardsSignalsReturnFalseForTrain
bool SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
Called by TAllRoutes::SetAllRearwardsSignals to set rearwards signals from a specified starting posit...
Definition: TrackUnit.cpp:17570
TRailGraphics::sm107
Graphics::TBitmap * sm107
Definition: GraphicUnit.h:778
TGraphicElement::LoadOverlayGraphic
void LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
Load the temporary overlay graphic.
Definition: TrackUnit.cpp:1859
TRailGraphics::bm75dblyellow
Graphics::TBitmap * bm75dblyellow
Definition: GraphicUnit.h:499
FailLockedRoute
@ FailLockedRoute
Definition: TrainUnit.h:40
TRailGraphics::sm32
Graphics::TBitmap * sm32
Definition: GraphicUnit.h:821
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all signals appropriately. Also called when a new train is added a...
Definition: TrackUnit.cpp:17332
TRailGraphics::sm44
Graphics::TBitmap * sm44
Definition: GraphicUnit.h:834
TRailGraphics::gl44
Graphics::TBitmap * gl44
Definition: GraphicUnit.h:664
TRailGraphics::bm36
Graphics::TBitmap * bm36
Definition: GraphicUnit.h:420
TRailGraphics::LCTopHor
Graphics::TBitmap * LCTopHor
Definition: GraphicUnit.h:742
Continuation
@ Continuation
Definition: TrackUnit.h:65
TRailGraphics::DirectionPrefDirGraphicsPtr
Graphics::TBitmap * DirectionPrefDirGraphicsPtr[10]
preferred direction marker arrows
Definition: GraphicUnit.h:1059
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:35
TTrack::GetFilletGraphic
Graphics::TBitmap * GetFilletGraphic(int Caller, TTrackElement TrackElement)
Return a pointer to the point fillet (the bit that appears to move when points are changed) for the p...
Definition: TrackUnit.cpp:7650
GraphicUnit.h
PerfLogUnit.h
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3748
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:6051
TOnePrefDir::FindLinkingCompatiblePrefDir
bool FindLinkingCompatiblePrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
Finds a pref dir element that is compatible and links to another element at given vector number and l...
Definition: TrackUnit.cpp:13473
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:86
TTrack::RightPlatAllowed
Set< int, 1, 146 > RightPlatAllowed
Definition: TrackUnit.h:589
TRailGraphics::bm12
Graphics::TBitmap * bm12
Definition: GraphicUnit.h:357
TTrack::DecrementValuesInInactiveTrackAndNameMaps
void DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the InactiveTrackVector, all the later elements are moved down ...
Definition: TrackUnit.cpp:9394
TRailGraphics::sm8
Graphics::TBitmap * sm8
Definition: GraphicUnit.h:869
TRailGraphics::sm87
Graphics::TBitmap * sm87
Definition: GraphicUnit.h:877
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:55
TRailGraphics::sm94
Graphics::TBitmap * sm94
Definition: GraphicUnit.h:885
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:12330
TTrack::LinkHVArray
int LinkHVArray[10][2]
array used to determine relative horizontal & vertical track element positions for specific link valu...
Definition: TrackUnit.h:575
TRailGraphics::sm49
Graphics::TBitmap * sm49
Definition: GraphicUnit.h:839
TRailGraphics::sm1
Graphics::TBitmap * sm1
Definition: GraphicUnit.h:769
TRailGraphics::sm84
Graphics::TBitmap * sm84
Definition: GraphicUnit.h:874
TTrack::TInfrastructureFailureEntry::FailureTime
TDateTime FailureTime
Definition: TrackUnit.h:712
TGraphicElement::ScreenGraphicLoaded
bool ScreenGraphicLoaded
Definition: TrackUnit.h:433
TTrack::TopPlatAllowed
Set< int, 1, 146 > TopPlatAllowed
Definition: TrackUnit.h:589
TRailGraphics::LinkPrefDirGraphicsPtr
Graphics::TBitmap * LinkPrefDirGraphicsPtr[30]
preferred direction graphic overlay
Definition: GraphicUnit.h:1048
TTrack::FailedPointsVector
TFailedElementVector FailedPointsVector
Definition: TrackUnit.h:794
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:3365
TGraphicElement::Height
int Height
dimensions in pixels
Definition: TrackUnit.h:437
TRailGraphics::sm98
Graphics::TBitmap * sm98
Definition: GraphicUnit.h:890
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1546
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:87
TRailGraphics::bm68green
Graphics::TBitmap * bm68green
Definition: GraphicUnit.h:457
TRailGraphics::gl79
Graphics::TBitmap * gl79
Definition: GraphicUnit.h:705
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:675
TTrack::SigTableGroundSignal
TSigElement SigTableGroundSignal[40]
new at version 0.6 for ground signals
Definition: TrackUnit.h:738
TAllRoutes::LockedRouteLastXLinkPos
int LockedRouteLastXLinkPos
Definition: TrackUnit.h:1708
TRailGraphics::sm113
Graphics::TBitmap * sm113
Definition: GraphicUnit.h:945
TRailGraphics::bm135
Graphics::TBitmap * bm135
Definition: GraphicUnit.h:370
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:266
TRailGraphics::LCBothVerMan
Graphics::TBitmap * LCBothVerMan
Definition: GraphicUnit.h:745
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:331
TRailGraphics::sm61
Graphics::TBitmap * sm61
Definition: GraphicUnit.h:853
TAllRoutes::DiagonalFouledByRouteOrTrain
bool DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
The track geometry allows diagonals to cross without occupying the same track element,...
Definition: TrackUnit.cpp:19903
TRailGraphics::bm73grounddblwhite
Graphics::TBitmap * bm73grounddblwhite
Definition: GraphicUnit.h:488
TOnePrefDir::CheckPrefDir4MultiMap
void CheckPrefDir4MultiMap(int Caller)
Diagnostic validity check.
Definition: TrackUnit.cpp:13270
TRailGraphics::BridgeSigRouteGraphicsPtr
Graphics::TBitmap * BridgeSigRouteGraphicsPtr[12]
route graphic for preferred routes overlay
Definition: GraphicUnit.h:1037
TRailGraphics::bm73dblyellow
Graphics::TBitmap * bm73dblyellow
Definition: GraphicUnit.h:486
TRailGraphics::sm111
Graphics::TBitmap * sm111
Definition: GraphicUnit.h:783
TOneRoute::TRouteFlashElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:1520
TRailGraphics::BridgeRouteAutoSigsGraphicsPtr
Graphics::TBitmap * BridgeRouteAutoSigsGraphicsPtr[12]
route graphic for automatic signal routes overlay
Definition: GraphicUnit.h:1041
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:84
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:53
TRailGraphics::bm106
Graphics::TBitmap * bm106
Definition: GraphicUnit.h:351
TRailGraphics::bm56
Graphics::TBitmap * bm56
Definition: GraphicUnit.h:450
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:790
TRailGraphics::gl146Striped
Graphics::TBitmap * gl146Striped
Definition: GraphicUnit.h:632
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:904
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0)
Definition: TrackUnit.cpp:4712
TRailGraphics::sm96striped
Graphics::TBitmap * sm96striped
Definition: GraphicUnit.h:888
TAllRoutes::StoreOneRoute
void StoreOneRoute(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector.
Definition: TrackUnit.cpp:18701
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1741
TTrack::DuplicatedLocationName
bool DuplicatedLocationName(int Caller, bool GiveMessage)
examines LocationNameMultiMap and returns true if there are two or more locations with the same name ...
Definition: TrackUnit.cpp:8704
TRailGraphics::gl87
Graphics::TBitmap * gl87
Definition: GraphicUnit.h:715
TTrack::THVPairsLinkedMap
std::map< THVPair, bool > THVPairsLinkedMap
added at v2.6.1 for use in PopulateHVPairsLinkedMapAndNoDuplicates
Definition: TrackUnit.h:695
TDisplay::Ellipse
void Ellipse(int Caller, int HPos, int VPos, TColor Col)
Plot an ellipse at the defined position and with the defined colour.
Definition: DisplayUnit.cpp:123
TRailGraphics::gl113
Graphics::TBitmap * gl113
Definition: GraphicUnit.h:593
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:812
TRailGraphics::gl49
Graphics::TBitmap * gl49
Definition: GraphicUnit.h:669
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:209
TTrack::OtherTrainOnTrack
bool OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
True if another train on NextEntryPos track of element at NextPos, whether bridge or not,...
Definition: TrackUnit.cpp:11039
TRailGraphics::sm38
Graphics::TBitmap * sm38
Definition: GraphicUnit.h:827
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:706
TOnePrefDir::SearchLimitHighV
int SearchLimitHighV
Definition: TrackUnit.h:1375
TOneRoute::SignalHasFailed
bool SignalHasFailed(int Caller)
Check incorporated in route search routines after have found a legitimate route, returns false for si...
Definition: TrackUnit.cpp:18133
TTrack::TInfrastructureFailureEntry::RepairTime
TDateTime RepairTime
Definition: TrackUnit.h:713
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:19740
TTrack::Tag77Array
int Tag77Array[25][3]
Definition: TrackUnit.h:579
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1869
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0)
Definition: TrackUnit.cpp:4695
Connection
@ Connection
Definition: TrackUnit.h:75
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3725
TRailGraphics::bm13
Graphics::TBitmap * bm13
Definition: GraphicUnit.h:360
TAllRoutes::RouteTruncateFlag
bool RouteTruncateFlag
used to flag the fact that a route is being truncated on order to change the behaviour of signal aspe...
Definition: TrackUnit.h:1716
TTrack::MarkOneLength
void MarkOneLength(int Caller, TTrackElement TE, bool FirstTrack, TDisplay *Disp)
Mark on screen a track element according to its length and speed limit if either of these differ from...
Definition: TrackUnit.cpp:9626
TRailGraphics::bmStraightNSSignalBlank
Graphics::TBitmap * bmStraightNSSignalBlank
Definition: GraphicUnit.h:1028
TRailGraphics::LCTopHorMan
Graphics::TBitmap * LCTopHorMan
Definition: GraphicUnit.h:749
TRailGraphics::bm75green
Graphics::TBitmap * bm75green
Definition: GraphicUnit.h:502
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:17145
TTrack::PopulateSimpleVector
void PopulateSimpleVector(int Caller)
clear then add all simple element track vector positions to the vector, added at v2....
Definition: TrackUnit.cpp:11559
TOnePrefDir::ConvertPrefDirSearchVector
void ConvertPrefDirSearchVector(int Caller)
Called after a successful search to add the elements from the search vector to the pref dir vector.
Definition: TrackUnit.cpp:12148
TRailGraphics::gl91set
Graphics::TBitmap * gl91set
Definition: GraphicUnit.h:723
TRailGraphics::sm37
Graphics::TBitmap * sm37
Definition: GraphicUnit.h:826
TTrack::ElementInLNPendingList
bool ElementInLNPendingList(int Caller, int MapPos)
Definition: TrackUnit.cpp:8630
TTrack::RepairTSR
void RepairTSR(TFailedElementVector::iterator FPVIt)
remove TSR, added at v2.13.0
Definition: TrackUnit.cpp:11531
TRailGraphics::sm86
Graphics::TBitmap * sm86
Definition: GraphicUnit.h:876
TRailGraphics::LinkGraphicsPtr
Graphics::TBitmap * LinkGraphicsPtr[30]
basic single track graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1046
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:19012
TAllRoutes::GetRouteElementDataFromRoute2MultiMap
TRouteElementPair GetRouteElementDataFromRoute2MultiMap(int Caller, int HLoc, int VLoc, TRouteElementPair &SecondPair)
Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function re...
Definition: TrackUnit.cpp:18968
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:7132
TPrefDirElement::GetPrefDirGraphicPtr
Graphics::TBitmap * GetPrefDirGraphicPtr()
picks up the EXGraphicPtr for preferred directions
Definition: TrackUnit.cpp:568
TTrack::PlatformOnSignalSide
bool PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *&SignalPlatformGraphic)
Check whether there is a platform present at HLoc & VLoc at the same side as the signal represented b...
Definition: TrackUnit.cpp:10910
TRailGraphics::gl80
Graphics::TBitmap * gl80
Definition: GraphicUnit.h:708
TRailGraphics::sm79
Graphics::TBitmap * sm79
Definition: GraphicUnit.h:867
TTrack::SigTable
TSigElement SigTable[40]
original table of signals for four aspect
Definition: TrackUnit.h:732
TOnePrefDir::TPrefDirVectorConstIterator
std::vector< TPrefDirElement >::const_iterator TPrefDirVectorConstIterator
Definition: TrackUnit.h:1402
TRailGraphics::smName
Graphics::TBitmap * smName
Definition: GraphicUnit.h:900
TRailGraphics::bm73grounddblred
Graphics::TBitmap * bm73grounddblred
Definition: GraphicUnit.h:487
TOneRoute::PointsToBeChanged
bool PointsToBeChanged(int Caller, int &NewFailedPointsTVPos) const
Definition: TrackUnit.cpp:17395
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:5839
TRailGraphics::sm7
Graphics::TBitmap * sm7
Definition: GraphicUnit.h:860
TRailGraphics::gl91unset
Graphics::TBitmap * gl91unset
Definition: GraphicUnit.h:724
TRailGraphics::bm50
Graphics::TBitmap * bm50
Definition: GraphicUnit.h:446
TDisplay::PlotSignalBlank
void PlotSignalBlank(int Caller, int HLoc, int VLoc, int SpeedTag, bool RHSFlag)
Definition: DisplayUnit.cpp:261
TTrackElement::TrainIDOnBridgeOrFailedPointOrigSpeedLimit01
int TrainIDOnBridgeOrFailedPointOrigSpeedLimit01
Definition: TrackUnit.h:154
TGraphicElement::OriginalLoaded
bool OriginalLoaded
Definition: TrackUnit.h:433
TTrack::OverrideAndHideSignalBridgeMessage
bool OverrideAndHideSignalBridgeMessage
if false signals facing bridges are not permitted, but can be set to true using CTRL ALT 5
Definition: TrackUnit.h:770
TTrack::SetStationEntryStopLinkPosses
void SetStationEntryStopLinkPosses(int Caller)
Called when trying to link track and when a name changed when track already linked.
Definition: TrackUnit.cpp:10086
TTrack::HLocMin
int HLocMin
Definition: TrackUnit.h:571
TTrack::SigTableThreeAspect
TSigElement SigTableThreeAspect[40]
new at version 0.6 for three aspect
Definition: TrackUnit.h:734
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:748
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:18238
TTrack::LinkTrack
bool LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
Attempt to link the track and return true if successful, if unsuccessful return error flag and positi...
Definition: TrackUnit.cpp:4839
TRailGraphics::sm16
Graphics::TBitmap * sm16
Definition: GraphicUnit.h:804
TTrack::ErrorInTrackBeforeSetGaps
bool ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
Check for track errors prior to gap setting - disused as incorporated a time-consuming double brute f...
Definition: TrackUnit.cpp:2761
TRailGraphics::gl69
Graphics::TBitmap * gl69
Definition: GraphicUnit.h:691
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7731
TRailGraphics::bm140
Graphics::TBitmap * bm140
Definition: GraphicUnit.h:388
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:3127
TRailGraphics::bm137
Graphics::TBitmap * bm137
Definition: GraphicUnit.h:376
TRailGraphics::sm64
Graphics::TBitmap * sm64
Definition: GraphicUnit.h:856
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:131
TRailGraphics::sm90
Graphics::TBitmap * sm90
Definition: GraphicUnit.h:881
TRailGraphics::bm136
Graphics::TBitmap * bm136
Definition: GraphicUnit.h:373
TOneRoute::SetRoutePoints
void SetRoutePoints(int Caller) const
Called when setting a route to set all points appropriately.
Definition: TrackUnit.cpp:17303
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:627
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen
Definition: DisplayUnit.h:76
TOnePrefDir::PresetAutoRouteElementValid
bool PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos)
Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entr...
Definition: TrackUnit.cpp:14065
TPrefDirElement::EntryExitNumber
bool EntryExitNumber()
determines and loads EXNumber (see above)
Definition: TrackUnit.cpp:320
TRailGraphics::bm101
Graphics::TBitmap * bm101
Definition: GraphicUnit.h:350
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:768
TRailGraphics::gl125
Graphics::TBitmap * gl125
Definition: GraphicUnit.h:606
TTrack::TLocationNameMultiMapRange
std::pair< TLocationNameMultiMapIterator, TLocationNameMultiMapIterator > TLocationNameMultiMapRange
Definition: TrackUnit.h:692
TUtilities::MaxRandomRepairTime
int MaxRandomRepairTime
Definition: Utilities.h:65
TTrack::RepairFailedSignals
void RepairFailedSignals(TFailedElementVector::iterator FPVIt)
restore signal to unfailed state, added at v2.13.0
Definition: TrackUnit.cpp:11469
TRailGraphics::gl145Striped
Graphics::TBitmap * gl145Striped
Definition: GraphicUnit.h:630
TRailGraphics::bm27
Graphics::TBitmap * bm27
Definition: GraphicUnit.h:395
TRailGraphics::bm73yellow
Graphics::TBitmap * bm73yellow
Definition: GraphicUnit.h:490
InRouteTrue
@ InRouteTrue
Definition: TrackUnit.h:1315
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:653
TRailGraphics::bm69yellow
Graphics::TBitmap * bm69yellow
Definition: GraphicUnit.h:464
TRailGraphics::FSig73
Graphics::TBitmap * FSig73
Definition: GraphicUnit.h:920
TTrack::TGapMapIterator
TGapMap::iterator TGapMapIterator
the first gap HLoc/VLoc pair, contains one entry for each pair of matched gaps
Definition: TrackUnit.h:663
TRailGraphics::bmTransparentBgnd
Graphics::TBitmap * bmTransparentBgnd
Definition: GraphicUnit.h:933
TRailGraphics::gl23
Graphics::TBitmap * gl23
Definition: GraphicUnit.h:641
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:11709
TRailGraphics::bm68grounddblwhite
Graphics::TBitmap * bm68grounddblwhite
Definition: GraphicUnit.h:456
TGraphicElement::OverlayPlotted
bool OverlayPlotted
Definition: TrackUnit.h:433
TRailGraphics::bm93unset
Graphics::TBitmap * bm93unset
Definition: GraphicUnit.h:516
TRailGraphics::sm122
Graphics::TBitmap * sm122
Definition: GraphicUnit.h:952
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:99
TOneRoute::TRouteFlashElement
A single flashing element of a route that flashes during setting.
Definition: TrackUnit.h:1516
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:198
TTrack::PopulateHVPairsLinkedMapAndNoDuplicates
bool PopulateHVPairsLinkedMapAndNoDuplicates(int Caller, TLocationNameMultiMapRange LNMMRg)
Used in checking for duplicate location names after Bill78 (discord name) developed the ....
Definition: TrackUnit.cpp:8753
TRailGraphics::sm26
Graphics::TBitmap * sm26
Definition: GraphicUnit.h:814
TDisplay::WarningLog
void WarningLog(int Caller, AnsiString Statement)
Display warning message Statement in the bottom left hand warning position and scroll other messages ...
Definition: DisplayUnit.cpp:522
TGraphicElement::~TGraphicElement
~TGraphicElement()
Destructor.
Definition: TrackUnit.cpp:1767
TTrack::SearchForAndUpdateLocationName
void SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
Checks all locations that are adjacent to the one entered for linked named location elements.
Definition: TrackUnit.cpp:8935
TUtilities::PointChangeEventsPerFailure
int PointChangeEventsPerFailure
number of points changes between failures - reciprocal of failure probability per change
Definition: Utilities.h:83
TRailGraphics::gl24
Graphics::TBitmap * gl24
Definition: GraphicUnit.h:642
TRailGraphics::gl109
Graphics::TBitmap * gl109
Definition: GraphicUnit.h:588
TTrack::TSigElement
Used as basic elements in a table of signals - see SigTable below.
Definition: TrackUnit.h:722
TOnePrefDir::GetOnePrefDirPosition
int GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
Although there may be up to four entries at one H & V position this function gets just one....
Definition: TrackUnit.cpp:13772
TAllRoutes::GetFixedRouteAtIDNumber
const TOneRoute & GetFixedRouteAtIDNumber(int Caller, IDInt RouteID) const
Returns a constant reference to the route with ID number RouteID. If no route is found with that ID a...
Definition: TrackUnit.cpp:19708
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise; points 0=set to ...
Definition: TrackUnit.h:142
TTrack::TBarrierState
TBarrierState
< state of barriers, values for level crossings either changing state or with barriers up or down
Definition: TrackUnit.h:609
TOnePrefDir::SearchLimitLowH
int SearchLimitLowH
Definition: TrackUnit.h:1372
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4372
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:818
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4586
TTrack::PlotSmallFlashingLinkedLevelCrossings
void PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
Plots either a LC or a blank element to flash manual LCs in zoomout mode.
Definition: TrackUnit.cpp:7594
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:1964
TRailGraphics::bmRedEllipse
Graphics::TBitmap * bmRedEllipse
Definition: GraphicUnit.h:527
TRailGraphics::LinkRouteAutoSigsGraphicsPtr
Graphics::TBitmap * LinkRouteAutoSigsGraphicsPtr[30]
auto signal route graphic overlay
Definition: GraphicUnit.h:1054
TTrack::SetBarriersDownLCToManual
void SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
Set TypeOfRoute value to 2 to indicate barriers manually closed.
Definition: TrackUnit.cpp:6396
TRailGraphics::bmDiagonalSignalBlank
Graphics::TBitmap * bmDiagonalSignalBlank
Definition: GraphicUnit.h:1025
TRailGraphics::gl83
Graphics::TBitmap * gl83
Definition: GraphicUnit.h:711
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:65
TRailGraphics::sm50
Graphics::TBitmap * sm50
Definition: GraphicUnit.h:841
TRailGraphics::gl25
Graphics::TBitmap * gl25
Definition: GraphicUnit.h:643
TRailGraphics::FSig68
Graphics::TBitmap * FSig68
Definition: GraphicUnit.h:915
TTrack::IsLCAtHV
bool IsLCAtHV(int Caller, int HLoc, int VLoc)
True if a level crossing is found at H & V.
Definition: TrackUnit.cpp:7389
Platform
@ Platform
Definition: TrackUnit.h:65
TOnePrefDir::SearchVector
TPrefDirVector SearchVector
pref dir vectors, first is the main vector, second used to store search elements temporarily
Definition: TrackUnit.h:1404
TPrefDirElement::EXGraphicPtr
Graphics::TBitmap * EXGraphicPtr
Definition: TrackUnit.h:211
TTrack::TGapMapEntry
std::pair< THVPair, THVPair > TGapMapEntry
Definition: TrackUnit.h:665
TRailGraphics::sm95
Graphics::TBitmap * sm95
Definition: GraphicUnit.h:886
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:778
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:704
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4611
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:792
TAllRoutes::TLockedRouteClass::LockStartTime
TDateTime LockStartTime
the timetable time at which the route is locked, to start the 2 minute clock
Definition: TrackUnit.h:1654
TRailGraphics::DirectionNonSigRouteGraphicsPtr
Graphics::TBitmap * DirectionNonSigRouteGraphicsPtr[10]
unrestricted route marker arrows
Definition: GraphicUnit.h:1061
TRailGraphics::sm11
Graphics::TBitmap * sm11
Definition: GraphicUnit.h:781
TTrack::RepairFailedPoints
void RepairFailedPoints(TFailedElementVector::iterator FPVIt)
restore points to unfailed state, added at v2.13.0
Definition: TrackUnit.cpp:11501
TRailGraphics::sm125
Graphics::TBitmap * sm125
Definition: GraphicUnit.h:955
TTrack::InactiveMapCheck
bool InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:8153
TRailGraphics::gl6
Graphics::TBitmap * gl6
Definition: GraphicUnit.h:681
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1328
TRailGraphics::sm23
Graphics::TBitmap * sm23
Definition: GraphicUnit.h:811
TRailGraphics::sm55
Graphics::TBitmap * sm55
Definition: GraphicUnit.h:846
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:9543
TRailGraphics::BridgePrefDirGraphicsPtr
Graphics::TBitmap * BridgePrefDirGraphicsPtr[12]
preferred direction graphic overlay
Definition: GraphicUnit.h:1035
TRailGraphics::sm10
Graphics::TBitmap * sm10
Definition: GraphicUnit.h:770
TTrack::FindClosestLinkPosition
int FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
Return the link array position for the element at StartTVPosition that gives the closest link to the ...
Definition: TrackUnit.cpp:11146
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1774
TRailGraphics::sm41
Graphics::TBitmap * sm41
Definition: GraphicUnit.h:831
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:95
TRailGraphics::gl22
Graphics::TBitmap * gl22
Definition: GraphicUnit.h:640
TOneRoute::TRouteFlashElement::HLoc
int HLoc
Definition: TrackUnit.h:1518
TRailGraphics::bm100
Graphics::TBitmap * bm100
Definition: GraphicUnit.h:349
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:16232
TTrack::LCInSearchVector
bool LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector)
checks for a route being set across an LC to prevent barriers raising
Definition: TrackUnit.cpp:7577
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:822
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:150
TRailGraphics::sm134
Graphics::TBitmap * sm134
Definition: GraphicUnit.h:796
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:145
TRailGraphics::gl71
Graphics::TBitmap * gl71
Definition: GraphicUnit.h:694
TOneRoute::TRouteFlashElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
displayed alternately during flashing
Definition: TrackUnit.h:1520
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:614
TTrack::AnyLinkedBarrierDownVectorManual
bool AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
Checks BarrierDownVector and returns true if there is one that is linked to the LC at H & V positions...
Definition: TrackUnit.cpp:6413
TRailGraphics::gl92set
Graphics::TBitmap * gl92set
Definition: GraphicUnit.h:725
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3625
TRailGraphics::sm102
Graphics::TBitmap * sm102
Definition: GraphicUnit.h:773
TRailGraphics::gl4
Graphics::TBitmap * gl4
Definition: GraphicUnit.h:659
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:99
TTrack::DefaultTrackSpeedLimit
int DefaultTrackSpeedLimit
speed limit of each track element before being changed within the program (can be changed in config....
Definition: TrackUnit.h:782
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:113
TTrack::Tag96Array
int Tag96Array[28][3]
Definition: TrackUnit.h:582
TRailGraphics::sm15
Graphics::TBitmap * sm15
Definition: GraphicUnit.h:803
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:754
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:11072
TRailGraphics::sm13
Graphics::TBitmap * sm13
Definition: GraphicUnit.h:790
TRailGraphics::sm91
Graphics::TBitmap * sm91
Definition: GraphicUnit.h:882
TOneRoute::SearchForNonPreferredRoute
bool SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, bool RecursiveCall)
Called by GetNextNonPreferredRouteElement to carry out the search for linked track,...
Definition: TrackUnit.cpp:16648
TRailGraphics::sm59
Graphics::TBitmap * sm59
Definition: GraphicUnit.h:850
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:150
THVPair
std::pair< int, int > THVPair
HLoc/VLoc position pair.
Definition: TrackUnit.h:40
TTrack::TLNPendingListIterator
TLNPendingList::iterator TLNPendingListIterator
naming of linked named location elements
Definition: TrackUnit.h:679
TRailGraphics::sm114
Graphics::TBitmap * sm114
Definition: GraphicUnit.h:946
TPrefDirElement::LogPrefDir
AnsiString LogPrefDir() const
Sends a list of PrefDirElement values to Utilities->CallLog file for debugging purposes.
Definition: TrackUnit.cpp:306
TRailGraphics::gl82
Graphics::TBitmap * gl82
Definition: GraphicUnit.h:710
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:623
TRailGraphics::gl95set
Graphics::TBitmap * gl95set
Definition: GraphicUnit.h:729
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:82
TPrefDirElement::operator==
bool operator==(TPrefDirElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:1074
TrainUnit.h
TRailGraphics::bm34
Graphics::TBitmap * bm34
Definition: GraphicUnit.h:414
TRailGraphics::gl104
Graphics::TBitmap * gl104
Definition: GraphicUnit.h:583
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag.=1, top=2, top rh diag....
Definition: TrackUnit.h:89
TTrack::TLNDone2MultiMapEntry
std::pair< THVPair, int > TLNDone2MultiMapEntry
can be up to 2 entries (platforms) at a single location
Definition: TrackUnit.h:686
TTrack::TrackMap
TTrackMap TrackMap
map of track (see type for more information above)
Definition: TrackUnit.h:826
RouteCall
@ RouteCall
Definition: TrackUnit.h:1321
TRailGraphics::bm141
Graphics::TBitmap * bm141
Definition: GraphicUnit.h:389
TTrackElement::TrainIDOnBridgeOrFailedPointOrigSpeedLimit23
int TrainIDOnBridgeOrFailedPointOrigSpeedLimit23
Definition: TrackUnit.h:154
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:11643
TRailGraphics::sm76striped
Graphics::TBitmap * sm76striped
Definition: GraphicUnit.h:862
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition, AnsiString TextToErase)
look for a text item in the vicinity of HPosInput & VPosInput & if TextToErase is null then erase any...
Definition: TextUnit.cpp:265
TRailGraphics::gl127
Graphics::TBitmap * gl127
Definition: GraphicUnit.h:608
TRailGraphics::bm75yellow
Graphics::TBitmap * bm75yellow
Definition: GraphicUnit.h:503
NotSet
@ NotSet
Definition: TrackUnit.h:75
TTrack::TInactiveTrack2MultiMapIterator
TInactiveTrack2MultiMap::iterator TInactiveTrack2MultiMapIterator
iterator for TInactiveTrack2MultiMap
Definition: TrackUnit.h:669
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:19284
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:88
TMapComp::operator()
bool operator()(const THVPair &lower, const THVPair &higher) const
HLoc VLoc.
Definition: TrackUnit.cpp:268
TRailGraphics::bm16
Graphics::TBitmap * bm16
Definition: GraphicUnit.h:392
TRailGraphics::gl128
Graphics::TBitmap * gl128
Definition: GraphicUnit.h:609
TRailGraphics::gl116
Graphics::TBitmap * gl116
Definition: GraphicUnit.h:596
TTrack::FailedSigTable
TSigElement FailedSigTable[8]
table of failed signals added at v2.13.0
Definition: TrackUnit.h:741
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:11101
TTrack::TrackClear
void TrackClear(int Caller)
Empty the track and inactive track vectors, the corresponding track maps, and LocationNameMultiMap.
Definition: TrackUnit.cpp:10362
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:674
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:533
TPrefDirElement::ELink
int ELink
Definition: TrackUnit.h:201
TRailGraphics::sm130striped
Graphics::TBitmap * sm130striped
Definition: GraphicUnit.h:792
TRailGraphics::sm118
Graphics::TBitmap * sm118
Definition: GraphicUnit.h:948
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:6314
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:160
LevelCrossing
@ LevelCrossing
Definition: TrackUnit.h:66
TRailGraphics::sm126
Graphics::TBitmap * sm126
Definition: GraphicUnit.h:956
TOneRoute::SearchForPreferredRoute
bool SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndSelectPosition, bool AutoSigsFlag, bool RecursiveCall)
Called by GetNextPreferredRouteElement to carry out the search for a valid route, and also called rec...
Definition: TrackUnit.cpp:15204
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:746
TOnePrefDir::GetModifiableSearchElementAt
TPrefDirElement & GetModifiableSearchElementAt(int Caller, int At)
Return a modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:11655
TOnePrefDir::TotalSearchCount
int TotalSearchCount
counts search elements, used to abort searches (prefdirs or routes) if reaches too high a value
Definition: TrackUnit.h:1377
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:54
TRailGraphics::bm18
Graphics::TBitmap * bm18
Definition: GraphicUnit.h:393
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:144
TTrack::~TTrack
~TTrack()
Destructor.
Definition: TrackUnit.cpp:1539
TRailGraphics::sm62
Graphics::TBitmap * sm62
Definition: GraphicUnit.h:854
TRailGraphics::LCBothVer
Graphics::TBitmap * LCBothVer
Definition: GraphicUnit.h:738
TRailGraphics::sm35
Graphics::TBitmap * sm35
Definition: GraphicUnit.h:824
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:50
TRailGraphics::gl81
Graphics::TBitmap * gl81
Definition: GraphicUnit.h:709
TTrack::HLocMax
int HLocMax
Definition: TrackUnit.h:571
TRailGraphics::gl146
Graphics::TBitmap * gl146
Definition: GraphicUnit.h:631
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:10353
Bridge
@ Bridge
Definition: TrackUnit.h:65
TTrack::DefaultTrackLength
int DefaultTrackLength
length of each track element before being changed within the program (can be changed in config....
Definition: TrackUnit.h:780
TRailGraphics::sm78
Graphics::TBitmap * sm78
Definition: GraphicUnit.h:865
TRailGraphics::bm43
Graphics::TBitmap * bm43
Definition: GraphicUnit.h:441
InRouteFalse
@ InRouteFalse
Definition: TrackUnit.h:1315
TRailGraphics::sm25
Graphics::TBitmap * sm25
Definition: GraphicUnit.h:813
TRailGraphics::bmName
Graphics::TBitmap * bmName
Definition: GraphicUnit.h:525
Gap
@ Gap
Definition: TrackUnit.h:75
Buffers
@ Buffers
Definition: TrackUnit.h:65
TOneRoute::SetRemainingSearchVectorValues
void SetRemainingSearchVectorValues(int Caller)
Called when setting unrestricted routes to set the route element values appropriately after a success...
Definition: TrackUnit.cpp:17061
TRailGraphics::gl79Striped
Graphics::TBitmap * gl79Striped
Definition: GraphicUnit.h:706
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:89
CrossConn
@ CrossConn
Definition: TrackUnit.h:75
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:11667
TRailGraphics::bm71grounddblwhite
Graphics::TBitmap * bm71grounddblwhite
Definition: GraphicUnit.h:475
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4523
TOnePrefDir::LastElementNumber
int LastElementNumber(int Caller) const
Return the vector position of the last element in the vector (i.e. one less than the vector size)
Definition: TrackUnit.cpp:11590
TRailGraphics::sm58
Graphics::TBitmap * sm58
Definition: GraphicUnit.h:849